{
  "openapi": "3.0.0",
  "paths": {
    "/v1/versions": {
      "get": {
        "operationId": "VersionsController_versions_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "summary": "API versions and deprecated routes with their sunset days. No key needed, not counted.",
        "tags": [
          "versions"
        ]
      }
    },
    "/v1/oauth/token": {
      "post": {
        "description": "Call it from your server, never from the app: the key stays on the server and the app gets a token that works for an hour, with the scopes you ask for. Send grant_type=client_credentials and the key as the HTTP Basic password (any user name, or the key prefix) or as client_secret, form encoded or JSON. Use the token like a key: ?access_token= or Authorization: Bearer. Limits, quota and usage are the key's. Revoking the key ends its tokens within a minute. A token cannot buy another token.",
        "operationId": "OAuthController_token_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequestDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_request, unsupported_grant_type, invalid_scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "invalid_client: the key is missing, wrong or revoked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthErrorDto"
                }
              }
            }
          }
        },
        "summary": "A short-lived token for an app, from your key. OAuth2 client credentials.",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/key": {
      "delete": {
        "description": "Only the calling key ends, never another key and never the org. The row is kept with revoked_at set. Calls with the key may still answer for up to 60 seconds (the key cache). Not counted, like /usage.",
        "operationId": "AccountController_revoke_v1",
        "parameters": [],
        "responses": {
          "204": {
            "description": "the key is ended"
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "no_key: it was already ended",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "End the key that makes this call.",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/usage": {
      "get": {
        "description": "Any key works, whatever its scopes, and sees only its own org. This call is free: it is not counted and does not use the daily quota, so it answers after the quota is reached. Days are Ulaanbaatar days.",
        "operationId": "AccountController_usage_v1",
        "parameters": [
          {
            "name": "days",
            "required": false,
            "in": "query",
            "description": "1 to 90, today included",
            "schema": {
              "example": 7,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_days",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "org_not_found: the org was closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your org's calls, tiles and door misses per day and per route, with its caps.",
        "tags": [
          "account"
        ]
      }
    },
    "/health": {
      "get": {
        "operationId": "HealthController_live",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "summary": "Liveness. The process is up.",
        "tags": [
          "health"
        ]
      }
    },
    "/health/ready": {
      "get": {
        "operationId": "HealthController_ready",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "summary": "Readiness. Database and PostGIS reachable.",
        "tags": [
          "health"
        ]
      }
    },
    "/v1/door/report": {
      "post": {
        "description": "The report is queued for review; door data does not change until a person reviews it (PLAN.md 19). The same report from the same organization within 24 h returns the first one (already_queued). A code that finds no door is 404 and counts against the daily door miss cap, like GET /v1/door/{code}. Notes: runs of 6 or more digits and e-mail addresses are removed. Never put a phone number or a name in a report.",
        "operationId": "DoorController_report_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DoorReportBodyDto"
              },
              "examples": {
                "wrong_location": {
                  "value": {
                    "kind": "wrong_location",
                    "code": "7QSVX",
                    "point": [
                      106.9303,
                      47.9202
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DoorReportDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_body, invalid_kind, invalid_code or invalid_point",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs door:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no door has code (or duplicate_of)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "410": {
            "description": "retired_code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "too_far: wrong_location point over 500 m from the door. not_accepted: reports are not taken at this point.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, quota_exceeded or miss_cap. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Report a wrong, missing, duplicate or unmapped door.",
        "tags": [
          "door"
        ]
      }
    },
    "/v1/door/at": {
      "get": {
        "description": "For a tap on the map. The хашаа containing the point answers first (in the ger areas the хашаа is the unit; a building inside a fence is its child), else the smallest current building containing it. code is null while the unit has no code yet. Nothing inside a restricted site. Not a code lookup: no miss cap, no resolution log.",
        "operationId": "DoorController_unitAt_v1",
        "parameters": [
          {
            "name": "lat",
            "required": true,
            "in": "query",
            "schema": {
              "example": 47.9384,
              "type": "number"
            }
          },
          {
            "name": "lon",
            "required": true,
            "in": "query",
            "description": "Longitude. lng is taken as an alias (Leaflet's and Google's name); send lon. Both sent must agree, else invalid_point.",
            "schema": {
              "example": 106.9011,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnitAtDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_point",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs door:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no unit at this point",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The address unit at a point: its code and official address.",
        "tags": [
          "door"
        ]
      }
    },
    "/v1/door/{code}/preview": {
      "get": {
        "description": "No key. For the web server that fills <title>, og:title and og:description of a shared code link (map.dock.mn/7QSVX) in chat apps that run no scripts. Only an address unit (a building or a khashaa) with a current code answers; it gives its Mongolian title (\"Сансар 8 · 7QSVX\"), its official line and its kind, and nothing else: no point, no person, no door. A building code, a retired code, a code inside a restricted site and an unknown code are all 404. Cached 5 minutes.",
        "operationId": "DoorController_preview_v1",
        "parameters": [
          {
            "name": "code",
            "required": true,
            "in": "path",
            "schema": {
              "example": "7QSVX",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "A code link's title and description, for a link preview.",
        "tags": [
          "door"
        ]
      }
    },
    "/v1/door/{code}": {
      "get": {
        "description": "Accepts lowercase and Cyrillic lookalike keys (В, К, М, Н, Р, С, Т, Х are read as the Latin letters they look like), and a flat number after a space (\"7QSVX 17\"), and the spoken form (\"7QSVX, 12 давхар, 1204 тоот\"). The official address comes first, the code after it (PLAN.md 4d). Anything not official_status matched is unofficial and must be shown as such. Codes are never reused: a retired code is 410. point is given to about 0.1 m: its 7th decimal is a mark for your organization (PLAN.md 19). Lookups that find no door (404) count against a daily cap per organization (default 200); at the cap this route answers 429 miss_cap until 00:00 Ulaanbaatar time.",
        "operationId": "DoorController_resolve_v1",
        "parameters": [
          {
            "name": "code",
            "required": true,
            "in": "path",
            "schema": {
              "example": "7QSVX",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A door. A code that names a whole building or khashaa answers a UnitCodeDto (kind building or khashaa).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DoorDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs door:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no door has this code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "410": {
            "description": "retired_code: the door was retired; the code is never reused",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, quota_exceeded or miss_cap. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Resolve a 5-character building code to its door.",
        "tags": [
          "door"
        ]
      }
    },
    "/v1/geocode": {
      "get": {
        "description": "Cyrillic and Latin, formal and informal spellings match (\"Баянзүрх\", \"Bayanzurkh\", \"bayanzurh\"). The state's street codes answer as kind street, first, with the state as source (\"СБД - 3 - 64\", \"SBD-3-64\", and the code a street was renamed from, \"Н-1-0012\"); no dock code. Ordinals fold (\"3-р хороо\", \"3r khoroo\"). Mongolian case endings fold (\"Дуурийн театр\", \"Гандангийн\"). One or two typos are tolerated. When names match fewer places than the limit, places whose description matches the meaning fill the rest (\"сургуулийн хажууд цэнхэр дээвэртэй барилга\"); those have layer 2 and come after every name match. A query that names a landmark and a side or \"near\" (\"Хүннү моллын ард\", \"east of Max Mall\", \"Max Mallの近く\") first lists the places within 150 m on that side, each with `near`, the landmark; when the query also describes the place, a reranking model orders the best of them on that description (layer 3). With proximity=lon,lat (where the person is, or the map centre), a name the query starts lists the nearer places of the same match first: whole name, then name start, then a later word, each nearer first. The point is not logged. A registered company (kind business, from a building directory) answers with its building's code, the building's official address, and the floor and flat the state register gives (null when it says none); the same place is never listed twice under one code and name. GET /v1/address/{id}/directory lists a building's companies by id or by code. Doors come with their official address first and the code after it (PLAN.md 4d); anything not matched is unofficial. Nothing inside a restricted site is returned. The query text is not logged. A point is given to about 0.1 m: its 7th decimal is a mark for your organization (PLAN.md 19). When the door_names feature is open to your org and the whole query is a live door name in any spelling that folds to it (\"сансар-бэйкери\"), the named door comes first, layer 1, with the best layer 1 score or 1.6, the score of a whole name, whichever is higher; it is not repeated below. The holder org is not shown. Serving it writes a resolution log row, as GET /v1/door-names/{name} does; no other result does. With types (door, business, building, district, khoroo, area, street, landmark, comma separated), only those kinds, up to limit of them, in every layer; the landmark a \"near\" query names is still found among every kind. A named door comes only when types has door. A query that is only a kind of place (\"банк\", \"эмийн сан\", \"шатахуун\", \"хоол\", \"pharmacy\") with proximity and no types lists the nearest registered places of that category, as GET /v1/nearby does, within 3 km, else 10 km, each with its category; none there, the name search answers. The bare word \"хашаа\" (or \"хашаанууд\") with proximity and no types lists the nearest minted хашаа units instead, within 3 km, else 10 km, nearest first: kind khashaa, the code, the official address and its line in long_mn, the name null; none there, the name search answers.",
        "operationId": "SearchController_geocode_v1",
        "parameters": [
          {
            "name": "types",
            "required": false,
            "in": "query",
            "description": "Comma separated: door, business, building, district, khoroo, area, street, landmark. Absent: every kind.",
            "schema": {
              "example": "street,area"
            }
          },
          {
            "name": "proximity",
            "required": false,
            "in": "query",
            "description": "lon,lat. Nearer places first among names the query starts equally well.",
            "schema": {
              "example": "106.9177,47.9186"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "1 to 20",
            "schema": {
              "example": 5,
              "type": "integer"
            }
          },
          {
            "name": "q",
            "required": true,
            "in": "query",
            "description": "1 to 200 characters",
            "schema": {
              "example": "Сансар А 8"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeocodeDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_query, invalid_limit, invalid_proximity or invalid_types",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs geocode:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Find doors and places by name, in Cyrillic or Latin.",
        "tags": [
          "search"
        ]
      }
    },
    "/v1/reverse": {
      "get": {
        "description": "District and khoroo come from polygons covering the point; a missing polygon is null, never a guess. Distance 0 means the point is inside the building. Nothing inside a restricted site is returned. With types (door, business, building, landmark, comma separated), only those kinds, up to limit of them. Without types, a point inside a minted хашаа (a ger plot) also gets that хашаа as a row of kind khashaa at distance 0: its code, its official address and its line in long_mn, the name null; a building that holds the point comes before it. A building inside a хашаа with no code of its own (one fence, one unit) carries the хашаа code in code, so the code to use is on its row too. A building row has no footprint_check; read it with GET /v1/address/{id} or the building tilequery. The top-level point is yours, as sent. Result points carry a mark for your organization in the 7th decimal (PLAN.md 19).",
        "operationId": "SearchController_reverse_v1",
        "parameters": [
          {
            "name": "types",
            "required": false,
            "in": "query",
            "description": "Comma separated: door, business, building, landmark. Absent: every kind.",
            "schema": {
              "example": "door,business"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "1 to 20",
            "schema": {
              "example": 5,
              "type": "integer"
            }
          },
          {
            "name": "radius",
            "required": false,
            "in": "query",
            "description": "metres, 1 to 1000",
            "schema": {
              "example": 50,
              "type": "number"
            }
          },
          {
            "name": "lon",
            "required": true,
            "in": "query",
            "description": "Longitude. lng is taken as an alias (Leaflet's and Google's name); send lon. Both sent must agree, else invalid_point.",
            "schema": {
              "example": 106.9376,
              "type": "number"
            }
          },
          {
            "name": "lat",
            "required": true,
            "in": "query",
            "schema": {
              "example": 47.9226,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReverseDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_point, invalid_radius, invalid_limit or invalid_types",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs geocode:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Doors, businesses, buildings and landmarks near a point, nearest first.",
        "tags": [
          "search"
        ]
      }
    },
    "/v1/nearby": {
      "get": {
        "description": "The categories are the map's place icons: a chip such as \"Эмийн сан\" is category=pharmacy, \"Хоол\" is category=restaurant,cafe. Banks, fuel, pharmacies, restaurants, cafes and shops are only businesses matched to an official registration; until one is, those categories answer an empty list, never a guess. A store of a registered chain (\"GS25 Нийслэл\") is kind business and carries the code of the building or хашаа it stands in (within 15 m of its pin); code is null, shown as \"код алга\", when there is none. Its official fields are that unit's, or none. A registered company of a nearby building (kind business, from the building directory) carries its building's code and the floor and flat the register gives; floor and flat are null on every other row. Each result has the fields of a reverse result plus its category. more counts the matches within radius past the limit, so a list of 20 can say there are 34 more. Nothing inside a restricted site is returned. The point is not logged. The top-level point is yours, as sent. Result points carry a mark for your organization in the 7th decimal (PLAN.md 19). Like reverse, it leaves footprint_check out; GET /v1/address/{id} has it.",
        "operationId": "SearchController_nearby_v1",
        "parameters": [
          {
            "name": "photo",
            "required": false,
            "in": "query",
            "description": "photo=1 adds photo to each result, as GET /v1/address/{id} gives it: one openly licensed Commons photo of a landmark or building, else null. One read instead of one per place.",
            "schema": {
              "example": true,
              "type": "boolean"
            }
          },
          {
            "name": "open",
            "required": false,
            "in": "query",
            "description": "open=1 keeps only places whose plain opening_hours tag says open now (open_now true), chosen before the limit from the nearest 20 places; more then counts the open ones past the limit. Unknown (null) is not open.",
            "schema": {
              "example": true,
              "type": "boolean"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "1 to 20",
            "schema": {
              "example": 10,
              "type": "integer"
            }
          },
          {
            "name": "radius",
            "required": false,
            "in": "query",
            "description": "metres, 1 to 10000. Left out: 1000 m, widened to 3000 m and then 10000 m when nothing is found.",
            "schema": {
              "example": 1000,
              "type": "number"
            }
          },
          {
            "name": "category",
            "required": true,
            "in": "query",
            "description": "Comma separated, at least one: atm, bank, bridge, cafe, car_wash, culture, embassy, fuel, government, hospital, hotel, kindergarten, mall, market, monument, office, park, pharmacy, religion, restaurant, school, shop, sport, station, stop, university.",
            "schema": {
              "example": "pharmacy"
            }
          },
          {
            "name": "lon",
            "required": true,
            "in": "query",
            "description": "Longitude. lng is taken as an alias (Leaflet's and Google's name); send lon. Both sent must agree, else invalid_point.",
            "schema": {
              "example": 106.9177,
              "type": "number"
            }
          },
          {
            "name": "lat",
            "required": true,
            "in": "query",
            "schema": {
              "example": 47.9186,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NearbyDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_point, invalid_category, invalid_radius, invalid_limit, invalid_open or invalid_photo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs geocode:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Places of one or more categories near a point, nearest first.",
        "tags": [
          "search"
        ]
      }
    },
    "/v1/address/{id}": {
      "get": {
        "description": "Same fields as a search result, plus `parents`: the ids of the building or khashaa, area, street, khoroo and district a door stands in (a business through its door); a khoroo carries its district only. Official address first, code after it (PLAN.md 4d); anything not matched is unofficial. Ids are never reused: a retired door, a demolished building or any retired place is 410. Something inside a restricted site is 404, retired or not. A place added since the last index refresh is 404 until the refresh. A door or business served writes a resolution log row (door, organization, time). point carries a mark for your organization in the 7th decimal (PLAN.md 19).",
        "operationId": "SearchController_address_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0192f0a4-7c1e-7a3b-9d2e-5b6c7d8e9f01",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_id: neither a UUID nor a 5-character building code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs geocode:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no current place has this id or code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "410": {
            "description": "retired: the place was retired; the id is never reused",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "One door or place by the id a geocode or reverse result gave.",
        "tags": [
          "search"
        ]
      }
    },
    "/v1/address/{id}/entrances": {
      "get": {
        "description": "For the building card: the id is a building's, from geocode, reverse or the building tile. Each entrance has its level (matched бүртгэлтэй, partial хэсэгчилсэн, none албан бус) and, once a door is minted for it, its code. An entrance with no door has the building's official form with its number, and no code. Generated entrances (confidence 0, source generated) are listed and say so: show them as таамаг. Nothing inside a restricted site. Writes no resolution log row: a building's list is no lookup of one door. Points carry a mark for your organization in the 7th decimal (PLAN.md 19).",
        "operationId": "SearchController_entrances_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0192f0a4-7c1e-7a3b-9d2e-5b6c7d8e9f01",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BuildingEntrancesDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_id: not a UUID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs geocode:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no current building has this id (or it is restricted). A landmark, business or stop id is not a building id, so it answers 404 by design: use the building id the same answer carries.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "410": {
            "description": "retired: the building was demolished or retired; the id is never reused",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "A building's entrances, each with its building code and official level, in one call.",
        "tags": [
          "search"
        ]
      }
    },
    "/v1/address/{id}/directory": {
      "get": {
        "description": "For \"Энд байгаа байгууллагууд\" on an office building or mall card: the id is a building's UUID or its 5-character unit code (a card that holds only the code can ask with it; a хашаа code answers an empty list). Each entry has name, floor, unit, category. Only organizations matched to an official registration are listed; a floor or unit the register does not give is null. Nothing inside a restricted site. Writes no resolution log row.",
        "operationId": "SearchController_directory_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "A building's UUID or its unit code.",
            "schema": {
              "example": "0192f0a4-7c1e-7a3b-9d2e-5b6c7d8e9f01",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BuildingDirectoryDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_id: not a UUID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs geocode:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no current building has this id (or it is restricted)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "410": {
            "description": "retired: the building was demolished or retired; the id is never reused",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The organizations registered in a building, by floor.",
        "tags": [
          "search"
        ]
      }
    },
    "/v1/entrances/near": {
      "get": {
        "description": "For a long-press on the map or \"Энд байгаа хаалга\" from the user's position: nearest first, within radius, up to limit (default 1). Each entrance as GET /v1/address/{id}/entrances lists it, plus its building and distance_m: its level (matched бүртгэлтэй, partial хэсэгчилсэн, none албан бус), its code once a door is minted, else the building's official form with its number and code null. Generated entrances (confidence 0, source generated) count and say so: show them as таамаг. Nothing inside a restricted site, nothing of a demolished building. Only buildings whose entrance method is approved appear; elsewhere the list is empty. Writes no resolution log row. Points carry a mark for your organization in the 7th decimal (PLAN.md 19); the top-level point is yours, as sent.",
        "operationId": "SearchController_entrancesNear_v1",
        "parameters": [
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "1 to 20",
            "schema": {
              "example": 1,
              "type": "integer"
            }
          },
          {
            "name": "radius",
            "required": false,
            "in": "query",
            "description": "metres, 1 to 1000",
            "schema": {
              "example": 50,
              "type": "number"
            }
          },
          {
            "name": "lon",
            "required": true,
            "in": "query",
            "description": "Longitude. lng is taken as an alias (Leaflet's and Google's name); send lon. Both sent must agree, else invalid_point.",
            "schema": {
              "example": 106.9301,
              "type": "number"
            }
          },
          {
            "name": "lat",
            "required": true,
            "in": "query",
            "schema": {
              "example": 47.9201,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NearEntrancesDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_point, invalid_radius or invalid_limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs geocode:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The building entrances nearest a point, each with its building code and official level.",
        "tags": [
          "search"
        ]
      }
    },
    "/v1/door-names": {
      "post": {
        "description": "The name is your org's for 365 days from registration; no fee is charged yet. Names are unique by their folded form: case, spaces, punctuation, and Latin letters typed for Cyrillic ones (\"Cансар\" with a Latin C) do not make another name. A name another org holds is 409 until it expires; then anyone may take it. Sending your own name with another code moves it (moved); the same code answers it (unchanged). Expiry does not change on either. At most 50 unexpired names per org. A code that finds no door is 404 and counts against the daily door miss cap, like GET /v1/door/{code}. Open to an org only when the door_names feature is (GET /v1/usage features); else 403 feature_off.",
        "operationId": "NamesController_register_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NameBodyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NameReceiptDto"
                }
              }
            }
          },
          "400": {
            "description": "error is one of invalid_body, invalid_name, name_is_code, personal_data, invalid_code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (needs names:write) or feature_off (door_names)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no door has this code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "name_taken: another org holds this name",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "410": {
            "description": "retired_code: the door was retired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "too_many: your org holds 50 unexpired names",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, quota_exceeded or miss_cap. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Register a spoken name for a door, or move your name to another door.",
        "tags": [
          "door-names"
        ]
      },
      "get": {
        "description": "Expired names stay listed, expired true, until another org takes them. transfer_until shows a transfer code you made that still works. Open to an org only when the door_names feature is (GET /v1/usage features); else 403 feature_off.",
        "operationId": "NamesController_own_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnNamesDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (needs names:write) or feature_off (door_names)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The names your org holds, A to Z.",
        "tags": [
          "door-names"
        ]
      }
    },
    "/v1/door-names/{name}": {
      "get": {
        "description": "Any spelling of the name that folds to the same key finds it: \"САНСАР БЭЙКЕРИ\", \"сансар-бэйкери\". The door is as GET /v1/door/{code} answers it, official address first; the holder org is not shown. An unknown or expired name, or one whose door was retired, is 404 and counts against the daily door miss cap. Open to an org only when the door_names feature is (GET /v1/usage features); else 403 feature_off.",
        "operationId": "NamesController_resolve_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "example": "Сансар бэйкери",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NamedDoorDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_name, name_is_code or personal_data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (needs door:read) or feature_off (door_names)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no door has this name",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, quota_exceeded or miss_cap. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Resolve a door name to its door.",
        "tags": [
          "door-names"
        ]
      }
    },
    "/v1/door-names/{name}/transfer-code": {
      "post": {
        "description": "Names are transferable, like a domain. The code is shown once; give it to the other org outside the API, and it claims the name with POST /v1/door-names/{name}/claim. It works for 7 days, or until the name expires if sooner, and only once. A new code replaces the old one. Until it is claimed the name stays yours: you may still move it or clear the code. Open to an org only when the door_names feature is (GET /v1/usage features); else 403 feature_off.",
        "operationId": "NamesController_offer_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "example": "Сансар бэйкери",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransferCodeDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_name, name_is_code or personal_data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (needs names:write) or feature_off (door_names)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: your org holds no unexpired name like this",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Make a transfer code for one of your names, to give it to another org.",
        "tags": [
          "door-names"
        ]
      },
      "delete": {
        "description": "After this the code is refused. Kept in history. Open to an org only when the door_names feature is (GET /v1/usage features); else 403 feature_off.",
        "operationId": "NamesController_cancel_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "example": "Сансар бэйкери",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransferCancelDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_name, name_is_code or personal_data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (needs names:write) or feature_off (door_names)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: your org holds no unexpired name like this",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Clear the transfer code of one of your names.",
        "tags": [
          "door-names"
        ]
      }
    },
    "/v1/door-names/{name}/claim": {
      "post": {
        "description": "The name becomes your org's. Its door and expires_at stay as they were; move it with POST /v1/door-names. The code is used up. A wrong, cleared or expired code is 409 transfer_refused and counts against the daily door miss cap, as an unknown name does. At most 50 unexpired names per org. Open to an org only when the door_names feature is (GET /v1/usage features); else 403 feature_off.",
        "operationId": "NamesController_claim_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "example": "Сансар бэйкери",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClaimBodyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClaimReceiptDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_name, name_is_code, personal_data or invalid_transfer_code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (needs names:write) or feature_off (door_names)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no unexpired name like this",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "transfer_refused: no such transfer code is waiting; already_yours: your org holds it",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "too_many: your org holds 50 unexpired names",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, quota_exceeded or miss_cap. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Take a name another org transfers to you, with the transfer code it gave you.",
        "tags": [
          "door-names"
        ]
      }
    },
    "/v1/changes": {
      "get": {
        "description": "Partner keys (changes:read). Ids, kinds and states only; fetch each current one with GET /v1/address/{id} (geocode:read). The window ends one second before the last index refresh (`until`), so every current id listed can be fetched; a newer change shows after the next refresh. One row per place, its last change, oldest first. A place is listed when its own record changes, or the record that places or names it: entrance, building, khashaa, area or street for a door; the door for a business; the area for a building. Nothing inside a restricted site is listed. First sync: since=1970-01-01T00:00:00Z lists every id served today.",
        "operationId": "ChangesController_changes_v1",
        "parameters": [
          {
            "name": "cursor",
            "required": false,
            "in": "query",
            "description": "`next` from the last page. since is then not needed.",
            "schema": {}
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "1 to 1000",
            "schema": {
              "example": 100,
              "type": "integer"
            }
          },
          {
            "name": "since",
            "required": false,
            "in": "query",
            "description": "ISO 8601 time with a zone (Z or +08:00). Inclusive. Needed unless cursor is given.",
            "schema": {
              "example": "2026-10-01T00:00:00Z"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChangesDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_since, invalid_limit or invalid_cursor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs changes:read, a partner key scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Which doors and places changed since a time, to keep copies in sync without a full pull.",
        "tags": [
          "search"
        ],
        "x-example-query": [
          "since"
        ]
      }
    },
    "/v1/confirm/own": {
      "get": {
        "description": "Counts by result for the month and for each day, the number of different drivers (by your driver ids, never the ids), and the failure points: up to 100 doors and entrances your drivers said are wrong, missing or a duplicate. A row counts on the Ulaanbaatar day the driver was on site (observed_at, else when received). The month you are in is answered too; closed is true from 8 days after the month ends, when no queued confirmation can join it. Needs confirm:read, a read-only scope for a dashboard key; confirm:write does not read it.",
        "operationId": "ConfirmController_ownMonth_v1",
        "parameters": [
          {
            "name": "month",
            "required": true,
            "in": "query",
            "description": "YYYY-MM, Ulaanbaatar calendar month",
            "schema": {
              "example": "2026-10"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConfirmOwnDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_month",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs confirm:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your own driver confirmations and door reports per month: your dashboard (PLAN.md 18). No other organization is read.",
        "tags": [
          "confirm"
        ]
      }
    },
    "/v1/confirm": {
      "post": {
        "description": "Partner keys (confirm:write); the free read key cannot write. The code is a building code or a unit code (a building or khashaa): an arrival at a unit code, result confirmed, is stored as one row on the unit (target unit, entrance null, next arrival) and raises no entrance. One row per confirmation; no point moves. A confirmed tap within 5 m raises the entrance to level 2 at once, and the hourly mint gives it a code within the hour; level 3 is three such stops on different days, or one and the customer's tap (PLAN.md 5). wrong_location and missing are reviewed by a person first. The tap is the placed point; device GPS must be within 40 m of it. The same driver saying the same thing within 24 h counts once (already_recorded). A code or entrance that finds nothing is 404 and counts against the daily door miss cap.",
        "operationId": "ConfirmController_confirm_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfirmBodyDto"
              },
              "examples": {
                "confirmed": {
                  "value": {
                    "result": "confirmed",
                    "code": "7QSVX",
                    "tap": [
                      106.9376,
                      47.9226
                    ],
                    "device": [
                      106.93765,
                      47.92265
                    ],
                    "driver": "drv-7f3a"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConfirmDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_body, invalid_result, invalid_code, invalid_entrance, invalid_point, invalid_driver or invalid_observed_at",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs confirm:write, a partner key scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no door has the code, or no entrance has the id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "410": {
            "description": "retired: the door or entrance was retired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "implausible: the tap is over 40 m from the phone GPS. too_far: the tap is over 500 m from the entrance or the unit (report it as unmapped). not_accepted: confirmations are not taken at this point. arrival_only: the code names a building or khashaa and the result was not confirmed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, quota_exceeded or miss_cap. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "A driver on site confirms a door or entrance, or says it is elsewhere or missing.",
        "tags": [
          "confirm"
        ]
      }
    },
    "/v1/confirm/{id}/photo": {
      "post": {
        "description": "The body is one JPEG as the camera saved it (Content-Type image/jpeg, up to 2 MB, 320 to 8000 px a side). Its metadata (EXIF with GPS, the phone, the time) is removed before it is stored; the orientation stays. Send it after POST /v1/confirm answered, with that id. One photo per confirmation: the same photo again is unchanged, another one is 409. Only your org's own confirmations; one in a restricted site is 404. A person reviews it once the entrance has a door; it is never shown on a public page.",
        "operationId": "ConfirmController_photo_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The id POST /v1/confirm answered.",
            "schema": {
              "format": "uuid",
              "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "image/jpeg": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConfirmPhotoDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_id, not_jpeg, invalid_photo, photo_too_small or photo_too_big",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs confirm:write",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no confirmation of yours has the id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "photo_exists: this confirmation has another photo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The photo of the door a driver took with one of your confirmations, for review.",
        "tags": [
          "confirm"
        ]
      }
    },
    "/v1/business/claim": {
      "post": {
        "description": "The claim waits as pending with its source and day. It is matched to the state legal-entity register by the register number; a business is published on its unit, with its code, only when it matches. Until then nothing is shown. The same register number and name from the same key within 24 h returns the first claim (already_queued). A key takes at most 20 claims a Ulaanbaatar day and one address at most 5, so one address cannot use up a shared key. The place is a unit code or a point, both optional.",
        "operationId": "ClaimController_claim_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BusinessClaimBodyDto"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessClaimDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_body, invalid_reg_number, invalid_name, invalid_phone, invalid_hours, invalid_sells, personal_data, invalid_code or invalid_point",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs door:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, quota_exceeded, claim_cap or claim_ip_cap. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "A business says it is here: five fields, no account.",
        "tags": [
          "business"
        ]
      }
    },
    "/v1/business/claim/{id}": {
      "get": {
        "description": "Answers only the key that sent the claim; any other id is 404. pending keeps the reason lane A wrote (not_in_register, name_differs) until the register or the claim changes. Name, phone and place are not returned.",
        "operationId": "ClaimController_status_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessClaimStatusDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs door:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Where a claim stands: pending, verified or refused, with the reason.",
        "tags": [
          "business"
        ]
      }
    },
    "/v1/business/photos/{id}": {
      "get": {
        "description": "Any other id, a photo the owner took off the card, or a card with fewer than 3 photos is 404.",
        "operationId": "ClaimController_photo_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0190a3c2-7b1e-7c3a-9d4e-5f6a7b8c9d0e",
              "type": "string"
            }
          }
        ],
        "responses": {
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "A photo listed on the card of a place whose claim the register confirmed.",
        "tags": [
          "business"
        ]
      }
    },
    "/v1/business/{id}/card": {
      "get": {
        "description": "Only for a business id (core.business or directory entry) whose registration number has a verified claim and a card; the same rule as claimed:true on /v1/search and /v1/nearby. Anything else is 404. Photos come only from 3 up, cover first, and are read from /v1/business/photos/{id}. buttons keep the owner order: the first is the main button, the second is the one the owner chose.",
        "operationId": "ClaimController_card_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicCardDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs door:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "What the owner put on the card of a claimed place: photos, buttons, menu and services, posts.",
        "tags": [
          "business"
        ]
      }
    },
    "/v1/merchant/login": {
      "post": {
        "operationId": "MerchantController_login_v1",
        "parameters": [],
        "responses": {
          "202": {
            "description": ""
          }
        },
        "summary": "Mails a sign-in link to this address. Always 202, whether the address is known or not.",
        "tags": [
          "business"
        ]
      }
    },
    "/v1/merchant/session": {
      "post": {
        "operationId": "MerchantController_session_v1",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "summary": "Spends a sign-in link (its token) for a session token, valid 30 days.",
        "tags": [
          "business"
        ]
      },
      "delete": {
        "operationId": "MerchantController_signOut_v1",
        "parameters": [],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "tags": [
          "business"
        ]
      }
    },
    "/v1/merchant/cards": {
      "get": {
        "operationId": "MerchantController_cards_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "summary": "The account and its cards: each with its claim state and the newest edit.",
        "tags": [
          "business"
        ]
      },
      "post": {
        "description": "The claim form's fields (POST /v1/business/claim) plus floor, stall and categories. At most 50 a day per account.",
        "operationId": "MerchantController_addCard_v1",
        "parameters": [],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "summary": "Claims a business at one place and opens its card. One account, many cards.",
        "tags": [
          "business"
        ]
      }
    },
    "/v1/merchant/cards/{id}": {
      "patch": {
        "operationId": "MerchantController_edit_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "example": "0190a3c2-7b1e-7c3a-9d4e-5f6a7b8c9d0e",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "summary": "Saves the card: any of hours, holidays, description, categories, phone, buttons, floor, stall, photos. Each save is kept with its day.",
        "tags": [
          "business"
        ]
      }
    },
    "/v1/merchant/cards/{id}/photos": {
      "post": {
        "operationId": "MerchantController_addPhoto_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "example": "0190a3c2-7b1e-7c3a-9d4e-5f6a7b8c9d0e",
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "summary": "Adds one JPEG to the card's photos, cleaned of EXIF; list it in photos (up to 10) to show it.",
        "tags": [
          "business"
        ]
      }
    },
    "/v1/merchant/register/{reg}": {
      "get": {
        "description": "Suggestions only; the owner accepts or changes each. phones_on_record is how many phones the register holds, never the numbers. 404 when the register does not hold the number.",
        "operationId": "MerchantController_register_v1",
        "parameters": [
          {
            "name": "reg",
            "required": true,
            "in": "path",
            "schema": {
              "example": "5071234",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "summary": "The state register's record for a registration number, to fill the claim form: name, legal form, legal address, categories, a building code to suggest.",
        "tags": [
          "business"
        ]
      }
    },
    "/v1/merchant/cards/{id}/verify/phone": {
      "post": {
        "operationId": "MerchantController_sendCode_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "example": "0190a3c2-7b1e-7c3a-9d4e-5f6a7b8c9d0e",
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": ""
          }
        },
        "summary": "Sends a 6-digit code to the phones the state register holds for the company. The answer masks them.",
        "tags": [
          "business"
        ]
      }
    },
    "/v1/merchant/cards/{id}/verify/phone/check": {
      "post": {
        "operationId": "MerchantController_checkCode_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "example": "0190a3c2-7b1e-7c3a-9d4e-5f6a7b8c9d0e",
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "summary": "Checks the code. 5 tries per code; a right code verifies the card.",
        "tags": [
          "business"
        ]
      }
    },
    "/v1/merchant/cards/{id}/verify/plate": {
      "post": {
        "operationId": "MerchantController_plate_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "example": "0190a3c2-7b1e-7c3a-9d4e-5f6a7b8c9d0e",
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "summary": "Activates the plate at the door with its key (XXXX-XXXX): the card is verified at that code. A plate activates once.",
        "tags": [
          "business"
        ]
      }
    },
    "/v1/merchant/cards/{id}/translate": {
      "post": {
        "description": "Only a language with no translation, or a machine one made from an older description, is redone; the owner's own stays. 503 translate_off when no model is set.",
        "operationId": "MerchantController_translateCard_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "example": "0190a3c2-7b1e-7c3a-9d4e-5f6a7b8c9d0e",
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": ""
          }
        },
        "summary": "Machine-translates the description into English, Korean, Japanese and Chinese, marked as machine translation.",
        "tags": [
          "business"
        ]
      }
    },
    "/v1/merchant/photos/{id}": {
      "get": {
        "operationId": "MerchantController_photo_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "example": "0190a3c2-7b1e-7c3a-9d4e-5f6a7b8c9d0e",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "tags": [
          "business"
        ]
      }
    },
    "/v1/tiles/{source}": {
      "get": {
        "description": "Tile URLs point back at this API. A key passed as ?access_token= is carried into them.",
        "operationId": "TilesController_tileJson_v1",
        "parameters": [
          {
            "name": "source",
            "required": true,
            "in": "path",
            "schema": {
              "example": "building",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "TileJSON 3.0.0"
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs tiles:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no such tile source",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "TileJSON for a tile source (building, entrance).",
        "tags": [
          "tiles"
        ]
      }
    },
    "/v1/tiles/{source}/{z}/{x}/{y}": {
      "get": {
        "description": "Tiles have no per-minute limit (since 0.78.0); they count against tile_daily_quota per organization per day (default 100,000). Other routes count against rate_limit and daily_quota.",
        "operationId": "TilesController_tile_v1",
        "parameters": [
          {
            "name": "source",
            "required": true,
            "in": "path",
            "schema": {
              "example": "building",
              "type": "string"
            }
          },
          {
            "name": "z",
            "required": true,
            "in": "path",
            "schema": {
              "example": 15,
              "type": "integer"
            }
          },
          {
            "name": "x",
            "required": true,
            "in": "path",
            "schema": {
              "example": 26115,
              "type": "integer"
            }
          },
          {
            "name": "y",
            "required": true,
            "in": "path",
            "schema": {
              "example": 11401,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Mapbox Vector Tile"
          },
          "204": {
            "description": "Empty tile"
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs tiles:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no such tile source",
            "content": {
              "application/x-protobuf": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "One Mapbox Vector Tile. 204 when the tile is empty.",
        "tags": [
          "tiles"
        ]
      }
    },
    "/v1/tiles/{sources}/tilequery/{point}": {
      "get": {
        "description": "sources is building or entrance or place, or both joined by a comma, as Mapbox's tileset list. point is lon,lat; a trailing .json is taken, as in Mapbox's path. radius 0, the default, finds what the point is inside; an entrance needs a radius. Each feature is a Point, the part of it nearest the point sent, with its tile fields and tilequery (distance, geometry, layer), as Mapbox's. The same rows as the tiles: current, not demolished, nothing in a restricted site, no building codes. Counts against rate_limit and daily_quota, not the tile budgets. Coverage: Ulaanbaatar.",
        "operationId": "TilequeryController_tilequery_v1",
        "parameters": [
          {
            "name": "sources",
            "required": true,
            "in": "path",
            "schema": {
              "example": "building,entrance",
              "type": "string"
            }
          },
          {
            "name": "point",
            "required": true,
            "in": "path",
            "schema": {
              "example": "106.9177,47.9186",
              "type": "string"
            }
          },
          {
            "name": "geometry",
            "required": false,
            "in": "query",
            "description": "only features of this type",
            "schema": {
              "enum": [
                "polygon",
                "linestring",
                "point"
              ],
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "1 to 50, default 5",
            "schema": {
              "example": 5,
              "type": "integer"
            }
          },
          {
            "name": "radius",
            "required": false,
            "in": "query",
            "description": "metres, 0 to 1000, default 0",
            "schema": {
              "example": 30,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TilequeryDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_point, invalid_radius, invalid_limit or invalid_geometry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs tiles:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no such tile source",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Features of one or more tile sources at or near a point, nearest first, as GeoJSON.",
        "tags": [
          "tiles"
        ]
      }
    },
    "/v1/route": {
      "get": {
        "description": "from and to are each a building code (\"7QSVX\") or lon,lat (\"106.9301,47.9201\"). A code is resolved to the street side of its building or the gate of its yard (PLAN.md 9 Phase 2) and needs door:read as well; it counts against the daily door miss cap like GET /v1/door/{code}. An end may also be an entrance id from GET /v1/address/{id}/entrances or GET /v1/entrances/near (needs geocode:read): the route ends at that entrance, never the building's middle, and to.entrance carries its code (null with no door yet), level and confidence (0 is generated, таамаг). The line follows the road network and ends where the network is nearest the entrance; to.gap_m is the straight walk left from there, which is never drawn as road. A code of a building or a yard ends at the gate when the map has one, else at the street side: the point of the building or yard outline nearest the street the line ends on, so the walk is the few metres from the street to the fence or wall, not to the middle. to.point is that end; to.unit.street_side is true when it is a gate, or within about 25 m of the street point. When the walk is over 15 m the last step says to leave the car (\"Машинаа тавиад хаалга хүртэл 17 м алхана уу.\", \"Leave the car and walk 17 m to the gate.\"); the arrival says \"Хаалга зүүн талд байна\", the gate and its side. An end given as a point, not a code, has no gate: its arrival says \"Очих газар зүүн талд байна\" (the destination and its side). No route starts or ends inside a restricted site (PLAN.md 20.2). Every road closure active today (GET /v1/closures) is avoided in every mode, and closures.avoided names them; over the router's limits for one request the route is refused, never a closure dropped. An end inside an active closure is refused with its id: the router has no road there. duration_s is free-flow. Driving routes also carry measured: the time with each road that has a published moving speed (GET /v1/traces/roads, the latest published month, 3+ partners) at that speed: all hours, or with depart_at the speeds of its hour band (GET /v1/traces/roads?band=), by its Ulaanbaatar weekday and hour. via passes up to 10 more ends on the way, in the order sent, as Mapbox's waypoints between the first and the last: each a code or lon,lat as from and to, and each refused as they are, named by its place (via[1]). The line may turn back at a via end. legs has one hop per pair, via the ends in order with where the line passes them. Coverage: Ulaanbaatar.",
        "operationId": "RouteController_route_v1",
        "parameters": [
          {
            "name": "heading_tolerance",
            "required": false,
            "in": "query",
            "description": "How far an edge may differ from heading, degrees 1 to 180. Default 45. Needs heading.",
            "schema": {
              "example": "45"
            }
          },
          {
            "name": "heading",
            "required": false,
            "in": "query",
            "description": "The direction of travel at from, degrees 0 to 359 (0 north, 90 east), from the phone's course. The route starts on the road edge that runs that way, so on a dual carriageway it is entered on the user's side with no U-turn. Left out: the nearest edge, either way.",
            "schema": {
              "example": "90"
            }
          },
          {
            "name": "depart_at",
            "required": false,
            "in": "query",
            "description": "Departure time, ISO 8601 with an offset (Z or +08:00; send + as %2B). Driving only: measured reads the speeds of its hour band: am_peak Monday to Friday, 07:00 to 09:59 Ulaanbaatar time; pm_peak Monday to Friday, 17:00 to 19:59 Ulaanbaatar time; off_peak every other hour, Saturday and Sunday whole. Left out: all hours. Past or future; the route itself does not change.",
            "schema": {
              "example": "2026-10-05T08:15:00+08:00"
            }
          },
          {
            "name": "via",
            "required": false,
            "in": "query",
            "description": "1 to 10 building codes or lon,lat joined by \";\", passed in this order between from and to. Left out: none.",
            "schema": {
              "example": "106.9250,47.9150;7QSVX"
            }
          },
          {
            "name": "mode",
            "required": false,
            "in": "query",
            "description": "default driving",
            "schema": {
              "enum": [
                "driving",
                "walking",
                "cycling"
              ],
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "schema": {
              "example": "7QSVX"
            }
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "schema": {
              "example": "106.9177,47.9186"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RouteDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_from, invalid_to, invalid_via, invalid_mode, invalid_depart_at or invalid_heading",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs route:read, door:read for a code, geocode:read for an entrance id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no door has this code, or no current entrance this id; for a via end the message names its place, as via[0]",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "410": {
            "description": "retired_code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "no_route: no road near a point, a point outside the map we route in (the Ulaanbaatar area), or no path between them, closures avoided. not_accepted: a point is in a restricted site. closures_over_limit: today's closures are more than the router takes in one request. end_in_closure: from, to or a via end is inside a closure active today.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, quota_exceeded or miss_cap. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Route between two points or building codes, through via ends in order. A code routes to the street side of its building or the gate of its yard, not the middle.",
        "tags": [
          "route"
        ]
      }
    },
    "/v1/matrix": {
      "get": {
        "description": "from and to are each 1 to 10 ends joined by \";\", each end as in GET /v1/route: a building code (\"7QSVX\", to its street side or gate; needs door:read as well) or lon,lat. durations_s[i][j] and distances_m[i][j] go from from[i] to to[j]; null where no path joins them. Every code is looked up and every one that is no door counts against the daily door miss cap, then the first is refused. Restricted sites and today's closures as GET /v1/route: an end in either is refused, every closure is avoided. Free-flow times only: no measured speeds, no depart_at, no line. One call, whatever the number of cells. Coverage: Ulaanbaatar.",
        "operationId": "MatrixController_matrix_v1",
        "parameters": [
          {
            "name": "mode",
            "required": false,
            "in": "query",
            "description": "default driving",
            "schema": {
              "enum": [
                "driving",
                "walking",
                "cycling"
              ],
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "schema": {
              "example": "7QSVX;106.9301,47.9201"
            }
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "schema": {
              "example": "106.9177,47.9186;106.9050,47.9210"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MatrixDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_from, invalid_to or invalid_mode",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs route:read, and door:read for a code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no door has a code; the message names its place, as to[1]",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "410": {
            "description": "retired_code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "no_route: an end has no road near it or is outside the map we route in (the Ulaanbaatar area), or the ends are further apart than the router takes. not_accepted: an end is in a restricted site. closures_over_limit, end_in_closure: as GET /v1/route.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, quota_exceeded or miss_cap. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Travel time and distance from every from to every to: up to 10 by 10 routes in one call.",
        "tags": [
          "route"
        ]
      }
    },
    "/v1/isochrone": {
      "get": {
        "description": "from is one end as in GET /v1/route: a building code (\"7QSVX\", from its entrance; needs door:read as well) or lon,lat. contours_minutes is 1 to 4 whole minutes up to 60, increasing, as Mapbox's. The answer is a GeoJSON FeatureCollection, one polygon per contour, largest first; add it to a map as a source. A code that is no door counts against the daily door miss cap. Restricted sites and today's closures as GET /v1/route: a from in either is refused, every closure is avoided. Free-flow times only: no measured speeds, no depart_at. Coverage: Ulaanbaatar.",
        "operationId": "IsochroneController_isochrone_v1",
        "parameters": [
          {
            "name": "mode",
            "required": false,
            "in": "query",
            "description": "default driving",
            "schema": {
              "enum": [
                "driving",
                "walking",
                "cycling"
              ],
              "type": "string"
            }
          },
          {
            "name": "contours_minutes",
            "required": true,
            "in": "query",
            "schema": {
              "example": "5,10,15"
            }
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "schema": {
              "example": "106.9177,47.9186"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IsochroneDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_from, invalid_contours or invalid_mode",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs route:read, and door:read for a code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no door has the code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "410": {
            "description": "retired_code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "no_route: from has no road near it, or is outside the map we route in (the Ulaanbaatar area). not_accepted: from is in a restricted site. closures_over_limit, end_in_closure: as GET /v1/route.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, quota_exceeded or miss_cap. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The area reached from one end within each of up to 4 times, as GeoJSON polygons.",
        "tags": [
          "route"
        ]
      }
    },
    "/v1/matching": {
      "get": {
        "description": "coordinates is 2 to 100 points as lon,lat joined by \";\", in the order recorded, as Mapbox's. timestamps, optional, is one Unix time in seconds per point; with them two far points seconds apart are a break, not a fast road. The answer has one matching per unbroken piece and one tracepoint per point, null where no road was found for it. A point inside a restricted site (PLAN.md 20.2) is left out before matching and is null too, as POST /v1/traces leaves it out; fewer than 2 points left refuses the trace. Today's closures are not avoided: a trace is where someone went. The trace is neither stored nor logged; to share a trip with the map, send it to POST /v1/traces. Coverage: Ulaanbaatar.",
        "operationId": "MatchingController_matching_v1",
        "parameters": [
          {
            "name": "mode",
            "required": false,
            "in": "query",
            "description": "default driving",
            "schema": {
              "enum": [
                "driving",
                "walking",
                "cycling"
              ],
              "type": "string"
            }
          },
          {
            "name": "timestamps",
            "required": false,
            "in": "query",
            "schema": {
              "example": "1790000000;1790000030;1790000060"
            }
          },
          {
            "name": "coordinates",
            "required": true,
            "in": "query",
            "schema": {
              "example": "106.9177,47.9186;106.9200,47.9188;106.9230,47.9190"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MatchDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_coordinates, invalid_timestamps or invalid_mode",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs route:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "no_match: no road near the trace. not_accepted: fewer than 2 points are outside restricted sites.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "A GPS trace matched to the road network: the roads it went along, and where each point lies on them.",
        "tags": [
          "route"
        ]
      }
    },
    "/v1/optimized-trips": {
      "get": {
        "description": "coordinates is 2 to 12 ends joined by \";\", each end as in GET /v1/route: a building code (\"7QSVX\", to its street side or gate; needs door:read as well) or lon,lat. The trip starts at the first, as Mapbox's source=first. roundtrip true (the default) goes back to it; false ends at the last sent, as destination=last. The stops between are put in the order with the least time on the road. waypoints are the stops in the order sent, each with waypoint_index, its place in the trip. Every code is looked up and every one that is no door counts against the daily door miss cap, then the first is refused. Restricted sites and today's closures as GET /v1/route: a stop in either is refused, every closure is avoided. Free-flow times only, no time at the stops. Coverage: Ulaanbaatar.",
        "operationId": "OptimizedTripsController_optimizedTrips_v1",
        "parameters": [
          {
            "name": "mode",
            "required": false,
            "in": "query",
            "description": "default driving",
            "schema": {
              "enum": [
                "driving",
                "walking",
                "cycling"
              ],
              "type": "string"
            }
          },
          {
            "name": "roundtrip",
            "required": false,
            "in": "query",
            "description": "default true",
            "schema": {
              "enum": [
                "true",
                "false"
              ],
              "type": "string"
            }
          },
          {
            "name": "coordinates",
            "required": true,
            "in": "query",
            "schema": {
              "example": "106.9177,47.9186;7QSVX;106.9050,47.9210;106.9250,47.9150"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OptimizedTripDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_coordinates, invalid_roundtrip or invalid_mode",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs route:read, and door:read for a code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no door has a code; the message names its place, as coordinates[1]",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "410": {
            "description": "retired_code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "no_route: a stop has no road near it or is outside the map we route in (the Ulaanbaatar area), no road joins it to the others, or the stops are further apart than the router takes. not_accepted: a stop is in a restricted site. closures_over_limit, end_in_closure: as GET /v1/route.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited, quota_exceeded or miss_cap. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The order to visit stops in with the least time on the road, and the trip in that order.",
        "tags": [
          "route"
        ]
      }
    },
    "/v1/closures": {
      "get": {
        "description": "Every closure not over today: active now or starting later, so a phone that stays offline for a week still knows announced works. Send as exclude_polygons the rings of the items active on your route day (from <= route day, and route day <= to when to is set). A point closes a square of 30 m, a line a 15 m band: Valhalla drops every edge that crosses one, the whole edge between two junctions. Over 10000 m of ring or 100 vertices in one request Valhalla refuses: refuse the route, never drop a closure. ids_sha256 changes when a closure is added or lifted; it is the closures_sha256 of an offline pack index. One request counts as one call.",
        "operationId": "ClosuresController_list_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClosuresDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs route:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Road closures current today, with the ring Valhalla avoids. No partner name, no note.",
        "tags": [
          "closures"
        ]
      },
      "post": {
        "description": "One report per call, kept forever: never edited or deleted, lift it when the road opens. The sender is your key's organization. Routes on dock avoid it from its from day; GET /v1/closures serves it to every partner without your name or note. Confidence 0.5: one partner's word. No reports inside a restricted site. Send an Idempotency-Key so a retry after a timeout cannot store the report twice: the same key with the same body answers the first report, stores nothing and sets Idempotent-Replayed: true; the same key with another body is 422. Keys are per organization and never expire.",
        "operationId": "ClosuresController_add_v1",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "One per report, 1 to 64 of letters, digits and ._:- (a uuid fits). Reuse it only to retry the same body.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "7f3c2a9e-4b1d-4e8a-9c55-2d0f6b1a8e40"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClosureBodyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "headers": {
              "Idempotent-Replayed": {
                "description": "true when this answers an earlier POST with the same Idempotency-Key",
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClosureDto"
                }
              }
            }
          },
          "400": {
            "description": "error is one of not_an_object, unknown_field, bad_kind, bad_day, to_before_from, bad_note, note_has_phone, bad_geometry, outside_mongolia, line_too_long, too_complex, restricted, bad_lift, lift_before_from, lift_in_future, bad_idempotency_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs closures:write",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "idempotency_key_reused: the key stored a report with another body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Report a stretch or a crossing that cannot be driven: flooded, washed out, a bridge down, snow, mud, works.",
        "tags": [
          "closures"
        ]
      }
    },
    "/v1/closures/{id}": {
      "get": {
        "description": "Other organizations' ids are 404.",
        "operationId": "ClosuresController_get_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "example": "cl-000001",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClosureDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs closures:write",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "One of your reports, as stored, note included: your export (PLAN.md 20.13).",
        "tags": [
          "closures"
        ]
      }
    },
    "/v1/closures/{id}/lift": {
      "post": {
        "description": "The report stays, with lifted set. Lifting twice keeps the first day and answers it. Other organizations' ids are 404.",
        "operationId": "ClosuresController_lift_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "example": "cl-000001",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClosureLiftDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClosureDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_lift, lift_in_future or lift_before_from",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs closures:write",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The road is open again: lift one of your reports from a day, today by default.",
        "tags": [
          "closures"
        ]
      }
    },
    "/v1/clean": {
      "post": {
        "description": "Spans come back as typed (\"12 давхар\") and, under numbers, as values (floor 12). The building is a footprint id and point, with the method that found it and that method's share right on test rows. No state address register is matched yet (PLAN.md 4d), so every row the engine answers is unofficial. An ambiguous address gives up to 3 choices, each with a hint (PLAN.md 4b). A building in a restricted site is withheld, in choices too (PLAN.md 20.2). Coverage: Ulaanbaatar. When the door_names feature is open to your org and a whole row is a live door name, in any spelling that folds to it (\"сансар-бэйкери\"), the row answers that door: method door_name, the door's official address and status, its entrance point (marked for your org, as GET /v1/door/{code} marks it), the building the entrance is on (null for a gate on a plot), no choices, match_confidence null. The parsed parts stay as read. The holder org is not shown. Each such row writes one resolution log row; no other row does.",
        "operationId": "CleanController_clean_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CleanBodyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CleanDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs clean:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Clean up to 100 raw addresses: district, khoroo, building, entrance, floor, unit, matched building.",
        "tags": [
          "clean"
        ]
      }
    },
    "/v1/signup": {
      "post": {
        "description": "Makes a free organization with one key: door:read, geocode:read, route:read, tiles:read; 60 requests and 600 tiles a minute; 1,000 requests, 25,000 tiles and 50 door misses a day. The key is in this answer only. A few keys per address per day, and a cap on free keys per day for everyone; both reset at 00:00 Ulaanbaatar time. For more, ask dock for a partner key. The body may carry {\"email\": ...}, the account's contact (dock.mn/account): kept with the organization, never logged, never in an answer or an export; that address is the company's owner (GET /v1/org). {\"name\": ...} names the company (2 to 80 characters). The key also has org:admin: it makes the company's other keys (POST /v1/keys) and invites its people (POST /v1/org/invites). No body is fine.",
        "operationId": "SignupController_signup_v1",
        "parameters": [],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SignupBodyDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignupDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_email: the email is not an e-mail address. invalid_name: name is not 2 to 80 characters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "signup_limited: this address took its free keys today, or free keys for today are gone. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "summary": "A free company and its first key, at once. A name and an e-mail if you like.",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/org": {
      "get": {
        "operationId": "OrgController_org_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your company: name, plan, limits for all its keys together, its people (org:admin keys), its live keys.",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/keys": {
      "get": {
        "operationId": "OrgController_keys_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeysDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs org:admin",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your company's keys, by prefix; never a key itself, never another company's.",
        "tags": [
          "account"
        ]
      },
      "post": {
        "description": "The key is in this answer only. Its calls count in the company's daily limit with all its other keys. Up to 50 live keys.",
        "operationId": "OrgController_createKey_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KeyBodyDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NewKeyDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_name, invalid_scopes: a scope your key does not have",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "too_many_keys: 50 live keys",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "A new key for your company, with some of your key's scopes.",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/keys/{prefix}": {
      "delete": {
        "operationId": "OrgController_revokeKey_v1",
        "parameters": [
          {
            "name": "prefix",
            "required": true,
            "in": "path",
            "description": "The key's first 11 characters, as GET /v1/keys lists it.",
            "schema": {
              "example": "dk_0123abcd",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          },
          "404": {
            "description": "not_found: no live key of your company has this prefix",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Revoke one of your company's keys. It stops within a minute.",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/org/invites": {
      "post": {
        "description": "Answers a one-use link for 7 days; send it yourself (dock sends no e-mail yet). Opening it gives the person a key of their own: an admin your scopes, a developer your scopes but org:admin, a driver what the driver app needs. Inviting the same address again replaces the open link.",
        "operationId": "OrgController_invite_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InviteBodyDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InviteDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_email, invalid_role",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "member: this address is in your company already",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Invite a person to your company: admin, developer or driver.",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/org/invites/accept": {
      "post": {
        "operationId": "OrgController_accept_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AcceptBodyDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AcceptDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no open invite has this token (used, replaced or expired)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Accept an invite: the token from its link gives you your own key in that company.",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/orders/import": {
      "post": {
        "description": "Columns by their header (ref, address, note, in Mongolian or English), else ref, address, note. Other columns, such as the customer's name or phone, are not kept. An address is a building code, lon,lat, or words. One dock does not find as a door, building, business or landmark stays unlocated: listed, never planned, never a guessed point. Up to 500 rows.",
        "operationId": "DispatchController_import_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportBodyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_sheet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Deliveries from a spreadsheet: paste it (tabs) or send CSV; each address found by dock's search.",
        "tags": [
          "dispatch"
        ]
      }
    },
    "/v1/orders": {
      "get": {
        "operationId": "DispatchController_list_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeliveriesDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your company's open deliveries and those done in the last 24 hours, by driver and stop.",
        "tags": [
          "dispatch"
        ]
      }
    },
    "/v1/dispatch/plan": {
      "post": {
        "description": "Stops are split by bearing from the depot, the same number each, then each driver's order is the shortest round trip by road, closures avoided. Arrival times add 3 minutes a stop. Unlocated deliveries are left out.",
        "operationId": "DispatchController_plan_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlanBodyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlanDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_depot, invalid_drivers, no_drivers",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Plan the open deliveries over your drivers: who takes which, in what order, and when each arrives.",
        "tags": [
          "dispatch"
        ]
      }
    },
    "/v1/orders/{id}": {
      "patch": {
        "description": "driver: last on their list, its arrival time cleared until the next plan. point: an unlocated or misplaced delivery placed by the dispatcher, match point, confidence 1, source dispatcher; planned on the next plan.",
        "operationId": "DispatchController_reassign_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0192f0a4-7c1e-7a3b-9d2e-5b6c7d8e9f01",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReassignBodyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeliveryDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no open delivery of yours has this id, or no driver this e-mail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Give one delivery to another driver (driver), or put it where it is (point, from a search pick).",
        "tags": [
          "dispatch"
        ]
      }
    },
    "/v1/orders/{id}/track": {
      "post": {
        "operationId": "DispatchController_trackLink_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0192f0a4-7c1e-7a3b-9d2e-5b6c7d8e9f01",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackLinkDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "A link for the customer: status, arrival time, and the driver on a map while theirs is the next stop. A new link replaces the old.",
        "tags": [
          "dispatch"
        ]
      }
    },
    "/v1/track/{token}": {
      "get": {
        "operationId": "DispatchController_tracked_v1",
        "parameters": [
          {
            "name": "token",
            "required": true,
            "in": "path",
            "schema": {
              "example": "tr_0123456789abcdefghijklmn",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackedDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "What a tracking link shows: no key, no name, no phone; the driver only while this is their next stop.",
        "tags": [
          "dispatch"
        ]
      }
    },
    "/v1/track/{token}/door": {
      "post": {
        "operationId": "DispatchController_doorSaid_v1",
        "parameters": [
          {
            "name": "token",
            "required": true,
            "in": "path",
            "schema": {
              "example": "tr_0123456789abcdefghijklmn",
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DoorSaidDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "no_door: this delivery is not a door",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The customer taps \"энэ миний хаалга\" on the tracking link: their word that the delivery's door is theirs. With one delivered stop within 8 m it makes the door trusted (level 3). No photo, no name, once per delivery.",
        "tags": [
          "dispatch"
        ]
      }
    },
    "/v1/fleet/positions": {
      "get": {
        "operationId": "DispatchController_positions_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PositionsDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your drivers' latest fixes of the last 10 minutes, as the driver app sends them.",
        "tags": [
          "dispatch"
        ]
      }
    },
    "/v1/driver/jobs": {
      "get": {
        "operationId": "DispatchController_jobs_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JobsDto"
                }
              }
            }
          },
          "403": {
            "description": "not_driver: this key is not a driver's",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The driver app: this driver's stops today, in order. A driver's own key (their invite) only.",
        "tags": [
          "dispatch"
        ]
      }
    },
    "/v1/driver/position": {
      "post": {
        "operationId": "DispatchController_fix_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FixBodyDto"
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "invalid_point, invalid_accuracy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The driver app's latest fix; only the latest is kept.",
        "tags": [
          "dispatch"
        ]
      }
    },
    "/v1/driver/jobs/{id}/status": {
      "post": {
        "operationId": "DispatchController_status_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0192f0a4-7c1e-7a3b-9d2e-5b6c7d8e9f01",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StatusBodyDto"
              }
            }
          }
        },
        "responses": {
          "404": {
            "description": "not_found: not this driver's open stop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The driver marks one of their stops: arrived, delivered or failed. Delivered with the driver's fix of the last 2 minutes within 8 m of the door's entrance is a stop for that door (3 on three days, or 1 and the customer's word, make it trusted).",
        "tags": [
          "dispatch"
        ]
      }
    },
    "/v1/driver/jobs/{id}/later": {
      "post": {
        "operationId": "DispatchController_later_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0192f0a4-7c1e-7a3b-9d2e-5b6c7d8e9f01",
              "type": "string"
            }
          }
        ],
        "responses": {
          "404": {
            "description": "not_found: not this driver's open stop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The driver puts one of their open stops last in their list. Stops that are done stay where they are.",
        "tags": [
          "dispatch"
        ]
      }
    },
    "/v1/styles": {
      "post": {
        "description": "Every field is optional; a missing one takes the dock default. Entrance colors show confidence and are the same on every map. Or {\"name\", \"style\"}: a whole MapLibre style (version 8, as dock.mn/studio saves it), up to 512 KB, valid by the style spec, with access_token taken out of its URLs; a key left in it is refused. A style never changes: to change it, save a new one. Up to 100 per org.",
        "operationId": "StylesController_create_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StyleBodyDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StyleDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_style",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs tiles:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "style_limit: the org has 100 styles",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Save a map style: dock's colors and extrusion, or a whole MapLibre style. Returns its id.",
        "tags": [
          "styles"
        ]
      },
      "get": {
        "operationId": "StylesController_list_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StyleListDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs tiles:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your org's styles, newest first.",
        "tags": [
          "styles"
        ]
      }
    },
    "/v1/styles/{id}": {
      "get": {
        "description": "Pass the id to createMap as styleId, or this URL to maplibre-gl as style. A key passed as ?access_token= is carried into the source URLs. Only keys of the org that saved the style can read it.",
        "operationId": "StylesController_get_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "example": "st_7m4xq2b9kd",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "MapLibre style JSON. metadata[\"dock:style\"] is the id."
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs tiles:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no such style for this key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "A saved style as a MapLibre style (version 8), sources on this API.",
        "tags": [
          "styles"
        ]
      }
    },
    "/v1/alerts": {
      "post": {
        "description": "Fires at most once per Ulaanbaatar day, within about a minute. With webhook_url, each firing is one POST, signed in Dock-Signature with the webhook_secret returned here once. An alert never changes. Up to 20 per org. Not counted.",
        "operationId": "AlertsController_create_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AlertBodyDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertCreatedDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_alert",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "alert_exists, or alert_limit: the org has 20 alerts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Add a usage alert: tell me when today's calls, tiles or door misses pass a share of the daily cap.",
        "tags": [
          "account"
        ]
      },
      "get": {
        "operationId": "AlertsController_list_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertListDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your org's alerts, and their firings of the last 30 days. Not counted.",
        "tags": [
          "account"
        ]
      }
    },
    "/v1/telemetry/search": {
      "post": {
        "description": "Send only for users who opted in, with consent: \"opt_in\". Leave it off by default. dock keeps the text, the result count and the pick, with your organization and the Ulaanbaatar day; no key, IP, device, session or time of day. Runs of 6 or more digits and e-mail addresses are removed before storage. Searches teach area names and aliases (PLAN.md 18); anything shown outside dock is grouped, at least 5 searches a group. Send only what was typed into a place search, never a person's name. One request counts as one call.",
        "operationId": "TelemetryController_search_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchTelemetryBodyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchTelemetryDto"
                }
              }
            }
          },
          "400": {
            "description": "consent_required or invalid_body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs geocode:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Send up to 50 place searches your users made, and what they picked. Opt-in only.",
        "tags": [
          "telemetry"
        ]
      }
    },
    "/v1/traces": {
      "post": {
        "description": "Send only after the user said yes, with consent: \"opt_in\". Three keys and nothing else: any other key (device id, user, phone, speed, accuracy) refuses the whole upload. Points are [lon, lat, t], whole seconds UTC. dock keeps the points with your organization and the Ulaanbaatar day; no key, IP or device. Points inside a restricted site are not stored. The same trip sent twice is stored once. Raw points are erased after 90 days (PLAN.md 20.13); DELETE erases them now. One request counts as one call.",
        "operationId": "TracesController_add_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TraceBodyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraceStoredDto"
                }
              }
            }
          },
          "400": {
            "description": "error is one of not_json, not_an_object, unknown_field, bad_format, consent_required, bad_points, too_few_points, too_many_points, bad_point, outside_mongolia, bad_time",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:write",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "413": {
            "description": "too_large: over 2 MB; split the trip",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Send one trip a user recorded, dock.trace.v1, up to 20000 points. Opt-in only.",
        "tags": [
          "traces"
        ]
      }
    },
    "/v1/traces/cells": {
      "get": {
        "description": "A cell is shown only when at least 3 organizations sent trips through it that month and the trips left after taking out the biggest organization's are 5 or more. Every other cell is left out: no cell means too few, not zero. Test and internal organizations do not count. One fixed grid and whole months only, published 14 days after the month ends; trips received later are not counted, so a number changes only when a partner deletes a trip. Counts survive the 90-day erase of the raw points. No ids, times, orgs or lines.",
        "operationId": "TracesController_cells_v1",
        "parameters": [
          {
            "name": "bbox",
            "required": true,
            "in": "query",
            "description": "west,south,east,north; inside Mongolia; sides at most 1 degree",
            "schema": {
              "example": "106.7,47.8,107.2,48.0"
            }
          },
          {
            "name": "month",
            "required": true,
            "in": "query",
            "description": "YYYY-MM, Ulaanbaatar calendar month",
            "schema": {
              "example": "2026-08"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraceCellsDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_month, month_open (not yet published), bad_bbox",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs insights:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Trips per 500 m cell and month, all partners together. The only way trip data leaves dock (PLAN.md 19).",
        "tags": [
          "traces"
        ]
      }
    },
    "/v1/traces/speeds": {
      "get": {
        "description": "Each trip is cut into segments between its stored points. A segment counts when its points are 1 to 60 seconds apart, it moves at 3 to 130 km/h, and its midpoint is more than 200 m from the trip's first and last point: parking and the walk to the door are not road speed. It counts in the cell of GET /v1/traces/cells holding its midpoint. km_h is the counted meters over the counted seconds of all trips in the cell, to 0.1. A cell is shown only when at least 3 organizations had counted trips in it that month and the trips left after taking out the biggest organization's are 5 or more. Every other cell is left out: no cell means too few trips, not a slow or empty road. No trip count: GET /v1/traces/cells has one. Per cell: GET /v1/traces/roads has speed per road. Test and internal organizations do not count. Whole months only, published 14 days after the month ends; trips received later are not counted. Speeds survive the 90-day erase of the raw points. No ids, times, orgs or lines.",
        "operationId": "TracesController_speeds_v1",
        "parameters": [
          {
            "name": "bbox",
            "required": true,
            "in": "query",
            "description": "west,south,east,north; inside Mongolia; sides at most 1 degree",
            "schema": {
              "example": "106.7,47.8,107.2,48.0"
            }
          },
          {
            "name": "month",
            "required": true,
            "in": "query",
            "description": "YYYY-MM, Ulaanbaatar calendar month",
            "schema": {
              "example": "2026-08"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraceSpeedsDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_month, month_open (not yet published), bad_bbox",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs insights:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Moving speed per 500 m cell and month, all partners together: where traffic is slow (PLAN.md 18, 19).",
        "tags": [
          "traces"
        ]
      }
    },
    "/v1/traces/roads": {
      "get": {
        "description": "Each trip is matched to OSM ways with Valhalla map matching (Meili) when it is stored. A segment between two stored points counts on a way when both points matched that way, they are 1 to 60 seconds apart, it moves at 3 to 130 km/h, and its midpoint is more than 200 m from the trip's first and last point, the rule of GET /v1/traces/speeds. km_h is the counted meters over the counted seconds of all trips on the way, to 0.1. A road is shown only when at least 3 organizations had counted trips on it that month and the trips left after taking out the biggest organization's are 5 or more. Every other road is left out: no road means too few trips, not a slow or empty road. The line is dock's current road with that OSM id: a way dock has no road line for, or one crossing a restricted site, is left out. No trip count. Test and internal organizations do not count. Whole months only, published 14 days after the month ends; a trip is matched only before then. Speeds survive the 90-day erase of the raw points. No trip ids, times, orgs or trip lines. With band, only the trips that started in that hour band count, and each road passes the group rule on those trips alone: a road can be shown for all hours and left out of a band. rule.hours says which hours an answer covers.",
        "operationId": "TracesController_roads_v1",
        "parameters": [
          {
            "name": "band",
            "required": false,
            "in": "query",
            "description": "Hour band, by the Ulaanbaatar time of the trip's first stored point: am_peak Monday to Friday, 07:00 to 09:59 Ulaanbaatar time; pm_peak Monday to Friday, 17:00 to 19:59 Ulaanbaatar time; off_peak every other hour, Saturday and Sunday whole. Left out: all hours.",
            "schema": {
              "enum": [
                "am_peak",
                "pm_peak",
                "off_peak"
              ],
              "type": "string"
            }
          },
          {
            "name": "bbox",
            "required": true,
            "in": "query",
            "description": "west,south,east,north; inside Mongolia; sides at most 1 degree",
            "schema": {
              "example": "106.7,47.8,107.2,48.0"
            }
          },
          {
            "name": "month",
            "required": true,
            "in": "query",
            "description": "YYYY-MM, Ulaanbaatar calendar month",
            "schema": {
              "example": "2026-08"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraceRoadsDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_month, month_open (not yet published), bad_bbox, bad_band",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs insights:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Moving speed per road and month, all partners together: speed profiles per road (PLAN.md 18, 19).",
        "tags": [
          "traces"
        ]
      }
    },
    "/v1/traces/cells/own": {
      "get": {
        "description": "The same grid and months as GET /v1/traces/cells, your organization's trips only, every cell with one of them: no group rule, the trips are yours. The month you are in is answered too and grows as trips arrive; closed is true from 14 days after the month ends, when the counts are final. Trips received later are stored, not counted. Your DELETE /v1/traces/{id} takes a trip out; the 90-day erase of the raw points keeps it. Needs trace:read, a read-only scope for a dashboard key; trace:write does not read it.",
        "operationId": "TracesController_ownCells_v1",
        "parameters": [
          {
            "name": "bbox",
            "required": true,
            "in": "query",
            "description": "west,south,east,north; inside Mongolia; sides at most 1 degree",
            "schema": {
              "example": "106.7,47.8,107.2,48.0"
            }
          },
          {
            "name": "month",
            "required": true,
            "in": "query",
            "description": "YYYY-MM, Ulaanbaatar calendar month",
            "schema": {
              "example": "2026-10"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraceOwnCellsDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_month, bad_bbox",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your own trips per 500 m cell and month: your dashboard (PLAN.md 18, 20.13). No other organization is read.",
        "tags": [
          "traces"
        ]
      }
    },
    "/v1/traces/arrivals/own": {
      "get": {
        "description": "For each of your trips: whole minutes from the first point after it was last more than 200 m from its end, to its end, 60 meaning 60 or more. Circling inside 200 m counts; a trip that never left 200 m of its end is not counted. The minutes include parking and the walk to the door: compare months and places with them. Month totals with median, p75 and p90 (nearest rank), trips per minute, and up to 100 cells where trips ended, by trips of 5 minutes or more. The same grid and months as GET /v1/traces/cells/own; closed is true from 14 days after the month ends. Your DELETE /v1/traces/{id} takes a trip out; the 90-day erase of the raw points keeps it. Needs trace:read.",
        "operationId": "TracesController_ownArrivals_v1",
        "parameters": [
          {
            "name": "month",
            "required": true,
            "in": "query",
            "description": "YYYY-MM, Ulaanbaatar calendar month",
            "schema": {
              "example": "2026-10"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraceArrivalsDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_month",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your own arrival minutes per month: how long your trips spend in the last 200 m (PLAN.md 18). No other organization is read.",
        "tags": [
          "traces"
        ]
      }
    },
    "/v1/traces/hours/own": {
      "get": {
        "description": "Each of your trips counts once, in the Ulaanbaatar weekday (1 Monday to 7 Sunday) and hour (0 to 23) of its first stored point. Month total, 7 weekday counts, 24 hour counts, and every weekday and hour with trips. The same months as GET /v1/traces/cells/own; closed is true from 14 days after the month ends. Your DELETE /v1/traces/{id} takes a trip out; the 90-day erase of the raw points keeps it. Needs trace:read.",
        "operationId": "TracesController_ownHours_v1",
        "parameters": [
          {
            "name": "month",
            "required": true,
            "in": "query",
            "description": "YYYY-MM, Ulaanbaatar calendar month",
            "schema": {
              "example": "2026-10"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraceHoursDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_month",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your own trips per weekday and hour, per month: when your trips run (PLAN.md 18). No other organization is read.",
        "tags": [
          "traces"
        ]
      }
    },
    "/v1/traces/hours": {
      "get": {
        "description": "Each trip counts once, in the Ulaanbaatar weekday (1 Monday to 7 Sunday) and hour (0 to 23) of its first stored point. A weekday and hour is shown only when at least 3 organizations sent trips that started in it that month and the trips left after taking out the biggest organization's are 5 or more, the rule of GET /v1/traces/cells. Every other slot is left out: no slot means too few, not zero. No total, so a left-out slot cannot be worked out. Test and internal organizations do not count. Whole months only, published 14 days after the month ends; trips received later are not counted. Counts survive the 90-day erase of the raw points. No ids, places, times or orgs.",
        "operationId": "TracesController_hours_v1",
        "parameters": [
          {
            "name": "month",
            "required": true,
            "in": "query",
            "description": "YYYY-MM, Ulaanbaatar calendar month",
            "schema": {
              "example": "2026-08"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraceAllHoursDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_month, month_open (not yet published)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs insights:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Trips per weekday and hour and month, all partners together: road load by hour (PLAN.md 18, 19).",
        "tags": [
          "traces"
        ]
      }
    },
    "/v1/traces/khoroos": {
      "get": {
        "description": "Each trip counts once, in the Ulaanbaatar hour (0 to 23) of its last stored point and the khoroo holding the centre of the 500 m cell of GET /v1/traces/cells that point is in. A cell on a khoroo boundary counts whole in one khoroo. Current khoroo polygons only: a khoroo with no polygon is not shown. A khoroo and hour is shown only when at least 3 organizations had trips ending in it that month and the trips left after taking out the biggest organization's are 5 or more, the rule of GET /v1/traces/cells. Every other hour is left out: no hour means too few, not zero. No khoroo total. Test and internal organizations do not count. Whole months only, published 14 days after the month ends; trips received later are not counted. Counts survive the 90-day erase of the raw points. No trip ids, points, times or orgs.",
        "operationId": "TracesController_khoroos_v1",
        "parameters": [
          {
            "name": "month",
            "required": true,
            "in": "query",
            "description": "YYYY-MM, Ulaanbaatar calendar month",
            "schema": {
              "example": "2026-08"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraceKhoroosDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_month, month_open (not yet published)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs insights:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Trips per khoroo and hour of arrival and month, all partners together: where and when trips end (PLAN.md 18, 19).",
        "tags": [
          "traces"
        ]
      }
    },
    "/v1/traces/khoroos/own": {
      "get": {
        "description": "Each of your trips counts once, in the Ulaanbaatar hour (0 to 23) of its last stored point and the khoroo holding the centre of the 500 m cell of GET /v1/traces/cells that point is in, as GET /v1/traces/khoroos. A cell counts whole in one khoroo; where current polygons overlap, the first by district code and number. No group rule: the trips are yours. Month total, trips ending in no current khoroo polygon (no_khoroo), and one feature per khoroo with its total and every hour with trips. Khoroo polygons are missing today: until they are loaded every trip is in no_khoroo. The same months as GET /v1/traces/cells/own; closed is true from 14 days after the month ends. Your DELETE /v1/traces/{id} takes a trip out; the 90-day erase of the raw points keeps it. Needs trace:read.",
        "operationId": "TracesController_ownKhoroos_v1",
        "parameters": [
          {
            "name": "month",
            "required": true,
            "in": "query",
            "description": "YYYY-MM, Ulaanbaatar calendar month",
            "schema": {
              "example": "2026-10"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraceOwnKhoroosDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_month",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your own trips per khoroo and hour of arrival, per month: where and when your trips end (PLAN.md 18). No other organization is read.",
        "tags": [
          "traces"
        ]
      }
    },
    "/v1/traces/kinds/own": {
      "get": {
        "description": "Each of your trips counts once, by the building at its last stored point: the one whose footprint holds the point, else the nearest within 30 m. The kind is the building type when the trip was stored (apartment, ger_house, commercial, public, industrial, garage, other); unknown is a building with no type yet, none is no building within 30 m. A later change to the building does not move a trip already counted. A building inside a restricted site is not read. No group rule: the trips are yours. Month total and every kind with trips, most first. The same months as GET /v1/traces/cells/own; closed is true from 14 days after the month ends. Your DELETE /v1/traces/{id} takes a trip out; the 90-day erase of the raw points keeps it. Needs trace:read.",
        "operationId": "TracesController_ownKinds_v1",
        "parameters": [
          {
            "name": "month",
            "required": true,
            "in": "query",
            "description": "YYYY-MM, Ulaanbaatar calendar month",
            "schema": {
              "example": "2026-10"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraceKindsDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_month",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your own trips per kind of building at the trip end, per month: what kind of deliveries you make (PLAN.md 18). No other organization is read.",
        "tags": [
          "traces"
        ]
      }
    },
    "/v1/traces/{id}": {
      "get": {
        "description": "geometry is null once the trace was deleted or passed purge_after. Other organizations' ids are 404.",
        "operationId": "TracesController_get_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraceDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:write",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "One of your traces as GeoJSON, as stored: your export (PLAN.md 20.13).",
        "tags": [
          "traces"
        ]
      },
      "delete": {
        "description": "Deleting twice is fine: the second call also answers deleted: true. Other organizations' ids are 404.",
        "operationId": "TracesController_remove_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TraceDeletedDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:write",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Delete one of your traces now. The points and times are erased; the id is kept and never reused.",
        "tags": [
          "traces"
        ]
      }
    },
    "/v1/traffic/probes": {
      "post": {
        "description": "Open to an organization once its fleet contract with dock is signed (feature traffic.probes); that contract is the consent, so no driver is asked and none is named. Send every 30 seconds or so while the vehicle moves. Three keys and nothing else: any other key (driver, phone, plate, device, accuracy) refuses the batch. vehicle is a random token the app makes anew every 15 minutes. dock matches the points to roads at once and keeps only each road's moving meters and seconds per 15-minute window, with a tag that tells vehicles apart in that window; the points, the token and the tags are not kept, and the window's tags are gone when it closes, 5 minutes after it ends. Points inside a restricted site are not matched. One request counts as one call.",
        "operationId": "TrafficController_probes_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProbeBodyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProbedDto"
                }
              }
            }
          },
          "400": {
            "description": "error is one of not_an_object, unknown_field, bad_format, bad_vehicle, bad_points, bad_point, bad_time",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:write; feature_off: traffic.probes is not open to this org",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable: map matching or the database is down; the batch was not counted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Send one vehicle's last positions, dock.probe.v1, up to 900 points. Fleets under contract only.",
        "tags": [
          "traffic"
        ]
      }
    },
    "/v1/traffic/typical": {
      "get": {
        "description": "Open to the scope the public map key has (tiles:read) and counted like a tile request: it has no per-minute limit and counts against tile_daily_quota. Cached 5 minutes. The band is the Ulaanbaatar clock of this moment: am_peak (Monday to Friday 07:00 to 09:59), pm_peak (Monday to Friday 17:00 to 19:59) or off_peak. The speeds are the newest closed month that has any (GET /v1/traces/roads with that band), all partners together, each road passing the group rule (3 or more organizations, no single organization over a share). No trip, vehicle, probe, time or organization is in the answer. A road without enough traces is left out: no road means no speed, not an empty road. When no month has any road in the box, features is empty and typical.month is null. Show it as \"ердийн\" (typical.label), never as live. Draw at zoom 12 and up.",
        "operationId": "TrafficController_typicalRoads_v1",
        "parameters": [
          {
            "name": "bbox",
            "required": true,
            "in": "query",
            "description": "west,south,east,north; inside Mongolia; sides at most 1 degree",
            "schema": {
              "example": "106.7,47.8,107.2,48.0"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrafficTypicalNowAnswerDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_bbox",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs tiles:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The usual speed per road for this hour band, for the map layer. Never live, never one trip.",
        "tags": [
          "traffic"
        ]
      }
    },
    "/v1/traffic": {
      "get": {
        "description": "Windows are 15 minutes on the quarter hour; the answer is the last one that has ended, so it is 0 to 15 minutes old. A road is shown only when at least 5 vehicles of partner fleets had counted segments on it in the window. A segment counts when two probes of one vehicle are 1 to 60 seconds apart, move at 3 to 130 km/h, and both matched the same way: a vehicle standing still is not counted, so a jam reads as its crawling speed. km_h is the counted meters over the counted seconds on the way, to 0.1. Every other road is left out: no road means too few vehicles, not an empty road. The line is dock's current road with that OSM id; a road crossing a restricted site is left out. Test and internal organizations do not count. No organizations, vehicles or points. When no road passes the rule (no fleet probes now), the answer is typical: kind is \"typical\", the roads are the speeds of the hour band of this moment (GET /v1/traces/roads band) in the newest closed month that has any, window is null, vehicles is null, and typical names the band and month. Show it as \"ердийн\", never as live.",
        "operationId": "TrafficController_roads_v1",
        "parameters": [
          {
            "name": "bbox",
            "required": true,
            "in": "query",
            "description": "west,south,east,north; inside Mongolia; sides at most 1 degree",
            "schema": {
              "example": "106.7,47.8,107.2,48.0"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrafficDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_bbox",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs insights:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Live speed per road: the last 15 minutes that have ended, roads that 5 or more vehicles passed.",
        "tags": [
          "traffic"
        ]
      }
    },
    "/v1/events": {
      "post": {
        "description": "Open to an organization once its contract with dock is signed (feature events.live). The area is a box; participants' points outside it or outside the time are not stored. 15 minutes after ends_at every point is erased and only the heat cells stay. The event is never deleted.",
        "operationId": "EventsController_open_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EventBodyDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventDto"
                }
              }
            }
          },
          "400": {
            "description": "error is one of not_an_object, unknown_field, bad_name, bad_bbox, bad_time",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:write; feature_off: events.live is not open to this org",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Open an event: a name, an area and a time. Organizers under contract only.",
        "tags": [
          "events"
        ]
      }
    },
    "/v1/events/{id}": {
      "get": {
        "description": "Other organizations' ids are 404.",
        "operationId": "EventsController_get_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:read; feature_off: events.live is not open to this org",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "One of your events.",
        "tags": [
          "events"
        ]
      }
    },
    "/v1/events/{id}/positions": {
      "post": {
        "description": "Send every 10 seconds or so, only after the participant said yes in your app (consent opt_in). Four keys and nothing else: any other key (name, bib, phone, device, accuracy) refuses the batch. participant is a random token your app makes when it starts sending; dock keeps only a tag made from it with the event's own salt, and the salt is deleted when the event closes. Points outside the event's area or time, or in a restricted site, are not stored. The rest are erased 15 minutes after the event ends. One request counts as one call.",
        "operationId": "EventsController_positions_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EventPositionBodyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventPositionsDto"
                }
              }
            }
          },
          "400": {
            "description": "error is one of not_an_object, unknown_field, bad_format, consent_required, bad_participant, bad_points, bad_point, bad_time",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:write; feature_off: events.live is not open to this org",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "event_closed: the event ended more than 15 minutes ago; nothing was stored",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Send one participant's last positions, dock.position.v1, up to 900 points.",
        "tags": [
          "events"
        ]
      }
    },
    "/v1/events/{id}/live": {
      "get": {
        "description": "Nothing when fewer than 5 participants are live. Points are rounded to 4 decimals (about 10 m) and sorted by place; no participant id, name or tag, so two answers cannot be joined by id. Poll every 10 seconds or so. Empty once the event has closed.",
        "operationId": "EventsController_live_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventLiveDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:read; feature_off: events.live is not open to this org",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Live dots for your event's page: each participant's last point of the last 2 minutes.",
        "tags": [
          "events"
        ]
      }
    },
    "/v1/events/{id}/heat": {
      "get": {
        "description": "The whole event, or one 15-minute window with ?window=. Cells are EPSG:3857 squares of 150 units, about 100 m at Ulaanbaatar. A cell with fewer than 5 distinct participants is left out, and so is one touching a restricted site. While the event is open the cells grow; 15 minutes after its end they are final and stay after every point is erased.",
        "operationId": "EventsController_heat_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "format": "uuid",
              "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b",
              "type": "string"
            }
          },
          {
            "name": "window",
            "required": false,
            "in": "query",
            "description": "ISO time on the quarter hour inside the event; absent for the whole event",
            "schema": {
              "example": "2027-06-12T03:30:00Z"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventHeatDto"
                }
              }
            }
          },
          "400": {
            "description": "bad_window",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs trace:read; feature_off: events.live is not open to this org",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Heat per area for your event: participants per 100 m cell, cells with 5 or more.",
        "tags": [
          "events"
        ]
      }
    },
    "/v1/corridors": {
      "get": {
        "description": "Every corridor the steppe dashboard renders, ranked by the share of cross-sections with 3 or more ruts in its last clear year. A rank is a lead to check, not a finding: last years and confidence differ by corridor. Numbers come from Sentinel-2 at 10 m and are not field checked; null means unknown. Show the attribution lines with the numbers. One request counts as one call.",
        "operationId": "CorridorsController_list_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CorridorsDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs route:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable: no corridor facts on this server",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Steppe corridors, one compare row each: braided share, envelope, years, confidence.",
        "tags": [
          "corridors"
        ]
      }
    },
    "/v1/corridors/{name}": {
      "get": {
        "description": "The numbers the dashboard and its PDF show a ministry: clear years, stretch, rut km per year, braided share, envelope, pasture, hotspots, the recommended track, verified track km. No line is surer than confidence_cap. Business places are counted, and named only when matched to an official registration. One request counts as one call.",
        "operationId": "CorridorsController_one_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "description": "A name from GET /v1/corridors.",
            "schema": {
              "example": "bayanzag",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CorridorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs route:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable: no corridor facts on this server",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "One steppe corridor with every fact line: text, value, unit, confidence, source, caveat.",
        "tags": [
          "corridors"
        ]
      }
    },
    "/v1/door-names/{name}/notes": {
      "post": {
        "description": "Only the org that holds an unexpired name for the door may write. Mongolian, English or both, up to 500 characters each: which entrance, which sign, what to say at the gate. The note waits for a person to review it; GET /v1/door/{code} keeps serving the notes the map holds until then, and GET /v1/door-names/{name}/notes shows whether it was accepted. Writing again replaces your waiting text, kept in history; other orgs' notes for the same door are their own. A note may hold no phone number and no e-mail. A name your org does not hold, or whose door was retired, is 404. Open to an org only when the hotel.notes feature is (GET /v1/usage features); else 403 feature_off.",
        "operationId": "NotesController_write_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "example": "Сансар бэйкери",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotesBodyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteReceiptDto"
                }
              }
            }
          },
          "400": {
            "description": "error is one of invalid_name, name_is_code, invalid_body, invalid_notes, personal_data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (needs names:write) or feature_off (hotel.notes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: your org holds no unexpired name like this, or its door is gone",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Write access notes for the door your name points at, for review.",
        "tags": [
          "door-names"
        ]
      },
      "get": {
        "description": "Only the org that holds an unexpired name for the door may read, and it reads only the notes it wrote. Each note is waiting, accepted or refused, with the time a person reviewed it. A name your org does not hold, or whose door was retired, is 404, as when writing. Open to an org only when the hotel.notes feature is; else 403 feature_off.",
        "operationId": "NotesController_read_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "example": "Сансар бэйкери",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteListDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_name, name_is_code or personal_data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (needs names:write) or feature_off (hotel.notes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: your org holds no unexpired name like this, or its door is gone",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Your notes for the door your name points at, and whether each was accepted.",
        "tags": [
          "door-names"
        ]
      }
    },
    "/v1/door-names/{name}/photo": {
      "post": {
        "description": "Only the org that holds an unexpired name for the door may send. The body is one JPEG, Content-Type image/jpeg, up to 2 MB, 320 to 8000 px on a side: the entrance or gate as a guest sees it on arrival. Its metadata is removed before it is stored: GPS, the phone, the time, XMP, comments, thumbnails. The orientation stays. The picture waits for a person to review it, who refuses one that shows a face, a car plate or a phone number; once accepted, GET /v1/door-names/{name}/photo serves it. Sending again replaces your waiting photo, kept in history. A name your org does not hold, or whose door was retired, is 404. Open to an org only when the hotel.notes feature is (GET /v1/usage features); else 403 feature_off.",
        "operationId": "NotesController_photo_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "example": "Сансар бэйкери",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The JPEG file as the camera saved it.",
          "content": {
            "image/jpeg": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhotoReceiptDto"
                }
              }
            }
          },
          "400": {
            "description": "error is one of invalid_name, name_is_code, personal_data, not_jpeg, invalid_photo, photo_too_small, photo_too_big",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (needs names:write) or feature_off (hotel.notes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: your org holds no unexpired name like this, or its door is gone",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "413": {
            "description": "too_large: the body is over 2 MB",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Send a gate photo for the door your name points at, for review.",
        "tags": [
          "door-names"
        ]
      },
      "get": {
        "description": "Only the org that holds an unexpired name for the door may read, and it reads only its own photo: the newest one a person accepted, under any of its names for the door. A waiting or refused photo is never served, nor another org's. The body is the JPEG as stored, metadata removed, orientation kept; the ETag is its sha256, as the send answered it, and If-None-Match with it is 304. Show it inside your app only, never on a public page of the place. A name your org does not hold, whose door was retired or lies in a restricted site, or with no accepted photo, is 404. Open to an org only when the hotel.notes feature is; else 403 feature_off.",
        "operationId": "NotesController_served_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "example": "Сансар бэйкери",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The JPEG.",
            "content": {
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "304": {
            "description": "If-None-Match holds the ETag of the photo served now."
          },
          "400": {
            "description": "invalid_name, name_is_code or personal_data",
            "content": {
              "image/jpeg": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "image/jpeg": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (needs names:write) or feature_off (hotel.notes)",
            "content": {
              "image/jpeg": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: your org holds no unexpired name like this, its door is gone, or no photo of yours was accepted",
            "content": {
              "image/jpeg": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "image/jpeg": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "image/jpeg": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The accepted gate photo for the door your name points at, for your app to show your guests.",
        "tags": [
          "door-names"
        ]
      }
    },
    "/v1/audit": {
      "get": {
        "operationId": "AuditController_list_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditSampleListDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (needs audit:write) or not_internal",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Audit samples, newest first. Staff keys only.",
        "tags": [
          "audit"
        ]
      }
    },
    "/v1/audit/{tag}": {
      "get": {
        "description": "Items now inside a restricted site are left out and counted in hidden (PLAN.md 20.2).",
        "operationId": "AuditController_checklist_v1",
        "parameters": [
          {
            "name": "tag",
            "required": true,
            "in": "path",
            "schema": {
              "example": "2026-10",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditChecklistDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (needs audit:write) or not_internal",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no sample has this tag",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "One sample's checklist in walk order, with every answer so far. Staff keys only.",
        "tags": [
          "audit"
        ]
      }
    },
    "/v1/audit/{tag}/{seq}": {
      "patch": {
        "description": "Sets the item's answer; a second call corrects it, result null clears it. Every call is also kept, with the key, in audit.check. The device position is a check only: within 40 m of the checked point (no checked point: of the drawn point; no_access: 150 m). A checked point over 500 m from the drawn point is too_far.",
        "operationId": "AuditController_check_v1",
        "parameters": [
          {
            "name": "tag",
            "required": true,
            "in": "path",
            "schema": {
              "example": "2026-10",
              "type": "string"
            }
          },
          {
            "name": "seq",
            "required": true,
            "in": "path",
            "schema": {
              "example": 1,
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AuditCheckBodyDto"
              },
              "examples": {
                "found": {
                  "value": {
                    "result": "found",
                    "checked": [
                      106.930113,
                      47.920104
                    ],
                    "method": "rtk",
                    "device": [
                      106.93013,
                      47.92012
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditCheckDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_body, invalid_result, invalid_point, invalid_method or invalid_checked_at",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (needs audit:write) or not_internal",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no item has this tag and seq",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "too_far, implausible (device too far), or not_accepted (a point in a restricted site)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "What the surveyor found at one item. Staff keys only.",
        "tags": [
          "audit"
        ]
      }
    },
    "/v1/venue": {
      "get": {
        "description": "Nearest first, at most 10. Use it to open an indoor map from a map position. One request counts as one call.",
        "operationId": "IndoorController_nearby_v1",
        "parameters": [
          {
            "name": "near",
            "required": true,
            "in": "query",
            "description": "lon,lat.",
            "schema": {
              "example": "106.7632,47.8431"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NearVenuesDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_near",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs door:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Venues at a point: the indoor maps whose outline holds it or lies within 200 m.",
        "tags": [
          "indoor"
        ]
      }
    },
    "/v1/venue/{id}": {
      "get": {
        "description": "Floors are current ones, lowest first. One request counts as one call.",
        "operationId": "IndoorController_venue_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Venue id (uuid).",
            "schema": {
              "example": "0198a2b4-1c3d-7e5f-8a9b-0c1d2e3f4a5b",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VenueDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs door:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "A venue: its outline and its floors.",
        "tags": [
          "indoor"
        ]
      }
    },
    "/v1/venue/{id}/level/{n}": {
      "get": {
        "description": "n is the floor number as people say it (0 ground, -1 basement). Each feature has feature_type, category, level, source and confidence.",
        "operationId": "IndoorController_level_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Venue id (uuid).",
            "schema": {
              "example": "0198a2b4-1c3d-7e5f-8a9b-0c1d2e3f4a5b",
              "type": "string"
            }
          },
          {
            "name": "n",
            "required": true,
            "in": "path",
            "description": "Floor number, an integer from -999 to 999.",
            "schema": {
              "example": 1,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LevelDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs door:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "One floor of a venue as GeoJSON: units, openings and amenities.",
        "tags": [
          "indoor"
        ]
      }
    },
    "/v1/venue/{id}/level/{n}/walk": {
      "get": {
        "description": "Corridor lines of floor n as GeoJSON LineStrings, plus the connectors that start or end on this floor (stairs, escalator, lift) with the floor they reach. The phone snaps each move to the nearest line within 25 m and offers a floor change at a connector.",
        "operationId": "IndoorController_levelWalk_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Venue id (uuid).",
            "schema": {
              "example": "0198a2b4-1c3d-7e5f-8a9b-0c1d2e3f4a5b",
              "type": "string"
            }
          },
          {
            "name": "n",
            "required": true,
            "in": "path",
            "description": "Floor number, an integer from -999 to 999.",
            "schema": {
              "example": 1,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalkNetDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs door:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The walk lines of one floor, for a phone that snaps its own steps to the corridors.",
        "tags": [
          "indoor"
        ]
      }
    },
    "/v1/venue/{id}/imdf": {
      "get": {
        "description": "manifest.json plus venue, building, level, unit, opening, amenity, anchor and occupant as GeoJSON FeatureCollections, current rows only. Every feature carries source and confidence in its properties; confidence null is unknown. Test fixtures are not served.",
        "operationId": "IndoorController_imdf_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Venue id (uuid).",
            "schema": {
              "example": "0198a2b4-1c3d-7e5f-8a9b-0c1d2e3f4a5b",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "application/zip",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs door:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "A venue as an IMDF archive (zip).",
        "tags": [
          "indoor"
        ]
      }
    },
    "/v1/venue/{id}/spot": {
      "get": {
        "description": "The link opens the indoor view on the unit. Nothing is invented: a unit without a name gets its number (\"305 тоот\"), else \"Сонгосон газар\".",
        "operationId": "IndoorController_spot_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Venue id (uuid).",
            "schema": {
              "example": "0198a2b4-1c3d-7e5f-8a9b-0c1d2e3f4a5b",
              "type": "string"
            }
          },
          {
            "name": "unit",
            "required": true,
            "in": "query",
            "description": "Unit id (uuid).",
            "schema": {
              "example": "0198a2b4-1c3d-7e5f-8a9b-0c1d2e3f4a5c"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IndoorSpotDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_unit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs door:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no such venue or unit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "What a printed plate for one unit says: venue, floor, name and the link its QR holds.",
        "tags": [
          "indoor"
        ]
      }
    },
    "/v1/venue/{id}/route": {
      "get": {
        "description": "from is where the walk starts, lon,lat, on floor from_level (default 0: the entrance the road route used, or a tapped spot). to is a unit id from GET /v1/venue/{id}/level/{n}. The walk follows the corridors drawn for the venue and takes stairs, escalators and lifts between floors (an escalator marked one-way is not taken the wrong way). A corridor with a drawn door that is closed now (its opening_hours) is not walked; when that leaves no way the answer is 422 no_open_route. Nothing is invented: where no corridor reaches the start or the unit, the answer is 422 no_route.",
        "operationId": "IndoorController_route_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Venue id (uuid).",
            "schema": {
              "example": "0198a2b4-1c3d-7e5f-8a9b-0c1d2e3f4a5b",
              "type": "string"
            }
          },
          {
            "name": "accessible",
            "required": false,
            "in": "query",
            "description": "1: step-free walk. Floors are joined by lifts only (no stairs, no escalators) and corridors marked with a step are left out; unknown corridors stay walkable.",
            "schema": {}
          },
          {
            "name": "to_kind",
            "required": false,
            "in": "query",
            "description": "Unit category (toilet, atm, ...): the unit of that kind with the shortest walk from the start. Ignored when to is given.",
            "schema": {
              "example": "restroom"
            }
          },
          {
            "name": "to",
            "required": false,
            "in": "query",
            "description": "Unit id (uuid). Give to or to_kind.",
            "schema": {
              "example": "0198a2b4-1c3d-7e5f-8a9b-0c1d2e3f4a5c"
            }
          },
          {
            "name": "from_level",
            "required": false,
            "in": "query",
            "description": "Floor number the start is on. Default 0.",
            "schema": {
              "example": 0,
              "type": "number"
            }
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "schema": {
              "example": "106.7632,47.8431"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IndoorRouteDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_from, invalid_from_level, invalid_to or invalid_to_kind",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs door:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no such venue or unit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "no_route: no corridor joins the start and the unit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The walk inside a venue to one unit, floor by floor, with steps in Mongolian.",
        "tags": [
          "indoor"
        ]
      }
    },
    "/v1/venue/{id}/directions": {
      "get": {
        "description": "from is lon,lat. The road goes by the routing engine to the venue's street entrances (an opening with an entrance id or the category \"entrance\"); the nearest 3 by straight line are tried and the quickest by road is taken. From that entrance the walk is the one GET /v1/venue/{id}/route gives, with steps in Mongolian and the floor on each. Nothing is invented: no drawn entrance is 422 no_entrance, no corridor from the entrance to the unit is 422 no_route.",
        "operationId": "IndoorController_directions_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "Venue id (uuid).",
            "schema": {
              "example": "0198a2b4-1c3d-7e5f-8a9b-0c1d2e3f4a5b",
              "type": "string"
            }
          },
          {
            "name": "accessible",
            "required": false,
            "in": "query",
            "description": "1: step-free walk. Floors are joined by lifts only (no stairs, no escalators) and corridors marked with a step are left out; unknown corridors stay walkable.",
            "schema": {}
          },
          {
            "name": "mode",
            "required": false,
            "in": "query",
            "description": "default driving",
            "schema": {
              "enum": [
                "driving",
                "walking",
                "cycling"
              ],
              "type": "string"
            }
          },
          {
            "name": "to",
            "required": true,
            "in": "query",
            "description": "Unit id (uuid).",
            "schema": {
              "example": "0198a2b4-1c3d-7e5f-8a9b-0c1d2e3f4a5c"
            }
          },
          {
            "name": "from",
            "required": true,
            "in": "query",
            "schema": {
              "example": "106.9177,47.9186"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IndoorDirectionsDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_from, invalid_to or invalid_mode",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope: needs route:read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "not_found: no such venue or unit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "422": {
            "description": "no_entrance, or no_route: no road to the entrance or no corridor to the unit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "The whole way to a unit: the road to the right entrance, then the walk inside, one answer.",
        "tags": [
          "indoor"
        ]
      }
    },
    "/v1/push/devices": {
      "post": {
        "description": "Idempotent. The list of codes replaces the earlier one. Not counted.",
        "operationId": "PushController_save_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PushDeviceBodyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PushDeviceDto"
                }
              }
            }
          },
          "400": {
            "description": "invalid_device",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Save this phone for push: its token and the building codes it follows.",
        "tags": [
          "account"
        ]
      },
      "delete": {
        "operationId": "PushController_forget_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PushForgetBodyDto"
              }
            }
          }
        },
        "responses": {
          "400": {
            "description": "invalid_device",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "missing_key, invalid_key or revoked_key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "no_device",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited. See Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          },
          "503": {
            "description": "unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "access_token": []
          }
        ],
        "summary": "Forget this phone: no more push to this token. The row is ended, not deleted.",
        "tags": [
          "account"
        ]
      }
    }
  },
  "info": {
    "title": "dock API",
    "description": "Doors, search and routing for Mongolia. Official address first, code after it.",
    "version": "0.118.0",
    "contact": {}
  },
  "tags": [],
  "servers": [
    {
      "url": "https://geo.dock.mn"
    },
    {
      "url": "http://localhost:13000"
    }
  ],
  "components": {
    "securitySchemes": {
      "access_token": {
        "type": "apiKey",
        "in": "query",
        "name": "access_token"
      },
      "bearer": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "type": "http"
      }
    },
    "schemas": {
      "TokenRequestDto": {
        "type": "object",
        "properties": {
          "grant_type": {
            "type": "string",
            "example": "client_credentials"
          },
          "client_secret": {
            "type": "string",
            "description": "Your key, when not sent as the HTTP Basic password."
          },
          "client_id": {
            "type": "string",
            "description": "Optional. When sent, the first 11 characters of the key (its prefix)."
          },
          "scope": {
            "type": "string",
            "description": "Space separated, at most the key's scopes. Absent: all of them.",
            "example": "door:read tiles:read"
          }
        },
        "required": [
          "grant_type"
        ]
      },
      "TokenDto": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string",
            "example": "dt_eyJ2IjoxLCJr..."
          },
          "token_type": {
            "type": "string",
            "example": "Bearer"
          },
          "expires_in": {
            "type": "number",
            "example": 3600,
            "description": "Seconds until the token stops working."
          },
          "scope": {
            "type": "string",
            "example": "door:read tiles:read"
          }
        },
        "required": [
          "access_token",
          "token_type",
          "expires_in",
          "scope"
        ]
      },
      "OAuthErrorDto": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "example": "invalid_client"
          },
          "error_description": {
            "type": "string"
          },
          "message": {
            "type": "string",
            "description": "The same text, under the name every other dock error uses."
          }
        },
        "required": [
          "error",
          "error_description",
          "message"
        ]
      },
      "ErrorDto": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "example": "invalid_code"
          },
          "message": {
            "type": "string"
          },
          "message_mn": {
            "type": "string",
            "example": "Код буруу байна. 5 тэмдэгт оруулна уу.",
            "description": "The same answer in short Mongolian, for a page to show."
          }
        },
        "required": [
          "error",
          "message",
          "message_mn"
        ]
      },
      "UsageCapsDto": {
        "type": "object",
        "properties": {
          "daily_quota": {
            "type": "integer",
            "example": 10000,
            "nullable": true,
            "description": "Requests per day across all keys, tiles apart. null = no cap."
          },
          "tile_daily_quota": {
            "type": "integer",
            "example": 100000,
            "nullable": true,
            "description": "Tile requests per day across all keys. null = no cap."
          },
          "door_miss_cap": {
            "type": "integer",
            "example": 200,
            "nullable": true,
            "description": "Door lookups per day that find no door. null = no cap."
          }
        },
        "required": [
          "daily_quota",
          "tile_daily_quota",
          "door_miss_cap"
        ]
      },
      "UsageUpgradeDto": {
        "type": "object",
        "properties": {
          "plan": {
            "type": "string",
            "example": "partner",
            "enum": [
              "partner"
            ]
          },
          "caps": {
            "description": "Daily caps after the move. Raised further per partner on request.",
            "allOf": [
              {
                "$ref": "#/components/schemas/UsageCapsDto"
              }
            ]
          },
          "rate_limit": {
            "type": "integer",
            "example": 60,
            "description": "Requests per minute per key."
          },
          "tile_rate_limit": {
            "type": "integer",
            "example": 1200,
            "description": "Kept for older clients; not enforced since 0.78.0 (tiles have no per-minute limit)."
          },
          "added_scopes": {
            "example": [
              "changes:read",
              "confirm:write"
            ],
            "description": "Scopes a partner key may add.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "plan",
          "caps",
          "rate_limit",
          "tile_rate_limit",
          "added_scopes"
        ]
      },
      "UsageKeyDto": {
        "type": "object",
        "properties": {
          "prefix": {
            "type": "string",
            "nullable": true,
            "example": "dk_7m4xq2b9",
            "description": "First 11 characters of the key that made this call."
          },
          "scopes": {
            "example": [
              "door:read",
              "geocode:read"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rate_limit": {
            "type": "integer",
            "example": 600,
            "description": "Requests per minute."
          },
          "tile_rate_limit": {
            "type": "integer",
            "example": 1200,
            "description": "Kept for older clients; not enforced since 0.78.0 (tiles have no per-minute limit)."
          }
        },
        "required": [
          "prefix",
          "scopes",
          "rate_limit",
          "tile_rate_limit"
        ]
      },
      "UsageDayDto": {
        "type": "object",
        "properties": {
          "day": {
            "type": "string",
            "example": "2026-10-01",
            "description": "Ulaanbaatar calendar day."
          },
          "calls": {
            "type": "integer",
            "example": 1219,
            "description": "Requests, tiles not included."
          },
          "tiles": {
            "type": "integer",
            "example": 408
          },
          "door_misses": {
            "type": "integer",
            "example": 3,
            "description": "Door lookups that found no door. Also counted in calls."
          },
          "keys": {
            "type": "integer",
            "example": 2,
            "description": "Keys that made at least one call that day."
          }
        },
        "required": [
          "day",
          "calls",
          "tiles",
          "door_misses",
          "keys"
        ]
      },
      "UsageEndpointDto": {
        "type": "object",
        "properties": {
          "endpoint": {
            "type": "string",
            "example": "GET /v1/door/:code",
            "description": "Method and route pattern. Never a code, a name or a query. Tiles are one route."
          },
          "calls": {
            "type": "integer",
            "example": 812,
            "description": "Requests to this route over the days asked, today included."
          },
          "misses": {
            "type": "integer",
            "example": 3,
            "description": "Of those, lookups that found no door. 0 for routes that never miss."
          }
        },
        "required": [
          "endpoint",
          "calls",
          "misses"
        ]
      },
      "UsageDto": {
        "type": "object",
        "properties": {
          "org": {
            "type": "string",
            "example": "Sansar Delivery LLC"
          },
          "plan": {
            "type": "string",
            "example": "custom",
            "enum": [
              "free",
              "custom"
            ],
            "description": "free: made by POST /v1/signup. custom: a partner org with caps set for it."
          },
          "upgrade": {
            "nullable": true,
            "description": "For a free org, what the partner plan gives. null for a partner org. Prices are not published yet.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/UsageUpgradeDto"
              }
            ]
          },
          "timezone": {
            "type": "string",
            "example": "Asia/Ulaanbaatar",
            "description": "Days run midnight to midnight here (UTC+8)."
          },
          "reset": {
            "type": "integer",
            "example": 1791561600,
            "description": "Unix seconds of the next Ulaanbaatar midnight, when caps reset."
          },
          "key": {
            "$ref": "#/components/schemas/UsageKeyDto"
          },
          "caps": {
            "$ref": "#/components/schemas/UsageCapsDto"
          },
          "features": {
            "example": [
              "cargo.eta"
            ],
            "description": "Features open to the org, A to Z. Routes of any other feature answer 403 feature_off. Empty when none is open. A change takes up to 60 s to show, like a revoked key.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "days": {
            "description": "Newest first, today included, one row per day, zeros kept.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UsageDayDto"
            }
          },
          "endpoints": {
            "description": "Every route your org called over the same days, most calls first, then A to Z. Routes with no calls are left out. The calls of all routes but tiles add up to the calls of the days; the tiles route to their tiles.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UsageEndpointDto"
            }
          }
        },
        "required": [
          "org",
          "plan",
          "upgrade",
          "timezone",
          "reset",
          "key",
          "caps",
          "features",
          "days",
          "endpoints"
        ]
      },
      "DoorReportBodyDto": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "wrong_location",
              "missing",
              "duplicate",
              "unmapped"
            ],
            "description": "wrong_location: the door is real but stands elsewhere (needs code, point). missing: there is no door where this code points (needs code). duplicate: two codes for one door (needs code, duplicate_of). unmapped: a real door that has no code (needs point, no code)."
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "description": "The reported door. Cyrillic lookalike keys are accepted."
          },
          "point": {
            "example": [
              106.9303,
              47.9202
            ],
            "description": "[lon, lat] WGS84 of the real door. wrong_location: within 500 m of the current entrance.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "duplicate_of": {
            "type": "string",
            "example": "M8N9P",
            "description": "For duplicate: the code the reported door duplicates."
          },
          "note": {
            "type": "string",
            "maxLength": 500,
            "description": "What a courier saw. Runs of 6 or more digits and e-mail addresses are removed before storing."
          }
        },
        "required": [
          "kind"
        ]
      },
      "DoorReportDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b",
            "description": "Report id. Same id for a repeat."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "already_queued"
            ],
            "description": "already_queued: your org sent the same report in the last 24 h; nothing new was stored."
          },
          "kind": {
            "type": "string",
            "example": "wrong_location"
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "nullable": true
          },
          "target": {
            "type": "string",
            "enum": [
              "door",
              "building",
              "plot"
            ],
            "nullable": true,
            "description": "What the report is attached to. unmapped: the building or plot at the point, null if the map has none."
          },
          "moved_m": {
            "type": "number",
            "example": 23.4,
            "nullable": true,
            "description": "wrong_location: metres from the current entrance."
          },
          "received_at": {
            "type": "string",
            "example": "2026-10-01T06:41:07.123Z"
          },
          "next": {
            "type": "string",
            "description": "Door data does not change until a person reviews the report.",
            "example": "review"
          }
        },
        "required": [
          "id",
          "status",
          "kind",
          "code",
          "target",
          "moved_m",
          "received_at",
          "next"
        ]
      },
      "OfficialAddressDto": {
        "type": "object",
        "properties": {
          "country": {
            "type": "string",
            "example": "MN",
            "description": "Country code, MN."
          },
          "city_or_aimag": {
            "type": "string",
            "example": "Улаанбаатар",
            "description": "The city or the aimag, for example Улаанбаатар."
          },
          "district_or_soum": {
            "type": "string",
            "example": "Баянзүрх",
            "description": "The district (дүүрэг) or the soum, without the word for it."
          },
          "khoroo_or_bag": {
            "type": "string",
            "example": "1-р хороо",
            "description": "The khoroo (хороо) or the bag, for example 3-р хороо."
          },
          "street_or_microdistrict": {
            "type": "string",
            "description": "The street (гудамж, өргөн чөлөө) or the microdistrict (хороолол) the building stands in."
          },
          "building_or_khashaa": {
            "type": "string",
            "description": "The building number, or the ger plot (хашаа) number, as the register writes it."
          },
          "entrance": {
            "type": "string",
            "description": "The entrance number, as the register writes it. Only when the register has one."
          },
          "floor": {
            "type": "string",
            "description": "The floor, as the register writes it. Only when the register has one."
          },
          "unit": {
            "type": "string",
            "description": "The flat or office number (тоот), as the register writes it. Only when the register has one."
          },
          "postal_code": {
            "type": "string",
            "example": "13381-0017",
            "description": "Unified postal code, zone and building (ХХЗХ, zipcode.mn)."
          },
          "building_name": {
            "type": "string",
            "description": "The building's own name in the state register; a purpose such as \"Орон сууц\" is not a name."
          }
        },
        "required": [
          "country",
          "city_or_aimag",
          "district_or_soum"
        ]
      },
      "UnitAtDto": {
        "type": "object",
        "properties": {
          "official_address": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ],
            "description": "The official address of the building or ger plot at the point."
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ],
            "description": "The level: matched бүртгэлтэй (state register), partial хэсэгчилсэн (public sources), none албан бус (not matched, shown as unofficial)."
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched. Clients must show \"unofficial\"."
          },
          "official_source": {
            "type": "string",
            "nullable": true,
            "description": "Where the official address came from, as the register and its record, for example zipcode:4364. null when there is none."
          },
          "official_date": {
            "type": "string",
            "nullable": true,
            "description": "The date the official address was recorded, YYYY-MM-DD. null when not known."
          },
          "source_date": {
            "type": "string",
            "example": "2026-10-19",
            "nullable": true,
            "description": "Date of the current door or unit row behind the code."
          },
          "kind": {
            "type": "string",
            "enum": [
              "building",
              "khashaa"
            ],
            "description": "building Барилга: a building with a code. khashaa Хашаа: a ger plot with a code."
          },
          "source": {
            "type": "string",
            "nullable": true,
            "example": "state",
            "description": "Where the unit row came from. null when unknown."
          },
          "confidence": {
            "type": "number",
            "nullable": true,
            "example": 2,
            "description": "How sure dock is of the building row, 0 to 4; lower for a state-only building. null for a khashaa or when unknown."
          },
          "official_line": {
            "type": "string",
            "nullable": true,
            "example": "Баянзүрх дүүрэг, 3-р хороо, Сансар, 8-р байр · 13381-0034",
            "description": "The official address as one Cyrillic line, postal code last. null when nothing is known."
          },
          "area_line": {
            "type": "string",
            "nullable": true,
            "example": "Хан-Уул дүүрэг, 1-р хороо",
            "description": "Where the point lies by the district and khoroo borders. Set when the address is not matched, and when a matched address names another district or soum than the point lies in (the register text stays in official_line). Unofficial, never an address. null otherwise."
          },
          "building_type": {
            "type": "string",
            "nullable": true,
            "example": "public",
            "description": "What the building is: apartment, ger_house, commercial, public, industrial, garage or other. null for a khashaa or when the building has no type yet; never guessed."
          },
          "opening_hours": {
            "type": "string",
            "nullable": true,
            "example": "Mo-Fr 09:00-18:00",
            "description": "The OpenStreetMap opening_hours tag of the landmark inside the building, as written. A tag can be old: show it as \"hours from OpenStreetMap\". null for a khashaa or when there is none; never guessed."
          },
          "hours_source": {
            "type": "string",
            "nullable": true,
            "example": "osm",
            "description": "Where opening_hours came from. null when opening_hours is null."
          },
          "building_levels": {
            "type": "number",
            "nullable": true,
            "example": 12,
            "description": "Floors above ground from the building record. null for a khashaa or when the building has none; never guessed."
          },
          "wheelchair": {
            "type": "string",
            "nullable": true,
            "enum": [
              "yes",
              "limited",
              "no"
            ],
            "example": "limited",
            "description": "Wheelchair access as OSM mappers recorded it for this building. null is unknown, never step free; only yes, limited and no are answers."
          },
          "outline": {
            "type": "object",
            "nullable": true,
            "example": {
              "type": "Polygon",
              "coordinates": [
                [
                  [
                    106.9203,
                    47.9135
                  ],
                  [
                    106.9215,
                    47.9135
                  ],
                  [
                    106.9215,
                    47.9122
                  ],
                  [
                    106.9203,
                    47.9135
                  ]
                ]
              ]
            },
            "description": "The building's whole footprint, GeoJSON Polygon or MultiPolygon in WGS84, simplified to about 0.5 m, 6 decimals. Draw the selection from this, not from map tiles, which cut a large building at tile edges. A khashaa answers its yard polygon. null when the unit has no polygon."
          },
          "parts": {
            "example": [
              {
                "code": "K0SR9",
                "name": "C блок",
                "levels": 35
              }
            ],
            "description": "Buildings that lie mostly inside this one (over 60 % of their area). Each keeps its own code, and that code opens this building. levels is the own floor count of the part, null when unknown, so two parts with one name can be told apart. name is null when the part has only a Latin name (the map reads Mongolian), the code and levels name it. Empty when none.",
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "host": {
            "type": "string",
            "nullable": true,
            "example": "T87ZW",
            "description": "When this code's building is a part of another, the host's code; open that code for the page. null for a host or a stand-alone building."
          },
          "complex_name": {
            "type": "string",
            "nullable": true,
            "example": "Нарны хороолол 3",
            "description": "The complex the building belongs to, from the official register. Not the building's own name. null when none."
          },
          "photo": {
            "type": "object",
            "nullable": true,
            "example": {
              "url": "https://upload.wikimedia.org/wikipedia/commons/a/a1/Shangri-La.jpg",
              "credit": "https://commons.wikimedia.org/wiki/File:Shangri-La.jpg",
              "license": "CC BY-SA 4.0",
              "source": "commons",
              "author": "A. Author"
            },
            "description": "One openly licensed Commons photo of the building, as GET /v1/address/{id} gives it: { url, credit, license, source, author? }. null when none. Show author, then credit and license."
          },
          "name_mn": {
            "type": "string",
            "nullable": true,
            "description": "The Mongolian name of the building or plot. null when it has none."
          },
          "name_en": {
            "type": "string",
            "nullable": true,
            "description": "The English name. null when it has none."
          },
          "point": {
            "example": [
              106.9177,
              47.9186
            ],
            "description": "[lon, lat] of a point inside the footprint, WGS84",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "code": {
            "type": "string",
            "nullable": true,
            "example": "7QSVX",
            "description": "null while the unit has no code yet"
          },
          "id": {
            "type": "string",
            "description": "Stable id of the unit (a building or a хашаа). Never shown to people as an address."
          }
        },
        "required": [
          "official_address",
          "official_status",
          "unofficial",
          "official_source",
          "official_date",
          "source_date",
          "kind",
          "source",
          "confidence",
          "official_line",
          "area_line",
          "building_type",
          "opening_hours",
          "hours_source",
          "building_levels",
          "wheelchair",
          "outline",
          "parts",
          "host",
          "complex_name",
          "photo",
          "name_mn",
          "name_en",
          "point",
          "code",
          "id"
        ]
      },
      "PreviewDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "7QSVX",
            "description": "The five-character code of the door or unit. Never used as an address."
          },
          "kind": {
            "type": "string",
            "enum": [
              "building",
              "khashaa"
            ],
            "description": "The kind of this object. building Барилга: a building with a code. khashaa Хашаа: a ger plot with a code."
          },
          "title_mn": {
            "type": "string",
            "example": "Сансар 8 · 7QSVX",
            "description": "Fits <title> and og:title."
          },
          "official_line": {
            "type": "string",
            "nullable": true,
            "description": "The official address line; null when none is matched.",
            "example": "Баянзүрх дүүрэг, 3-р хороо, Сансар, 8-р байр · 13381-0034"
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless the official address is matched."
          },
          "description_mn": {
            "type": "string",
            "example": "Баянзүрх дүүрэг, 3-р хороо, Сансар, 8-р байр · 13381-0034",
            "description": "Fits og:description. \" (албан бус)\" is added when unofficial."
          }
        },
        "required": [
          "code",
          "kind",
          "title_mn",
          "official_line",
          "unofficial",
          "description_mn"
        ]
      },
      "EntranceDto": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "door",
              "gate",
              "vehicle_gate",
              "stairwell"
            ],
            "description": "door: a door of a building. gate: a gate for people. vehicle_gate: a gate for vehicles. stairwell: a numbered stairwell entrance of a block."
          },
          "letter": {
            "type": "string",
            "example": "1",
            "nullable": true,
            "description": "Entrance or gate number as people say it."
          },
          "floors_served": {
            "nullable": true,
            "example": [
              1,
              9
            ],
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "The floors this entrance serves, as numbers. null when not known."
          }
        },
        "required": [
          "kind",
          "letter",
          "floors_served"
        ]
      },
      "UnitDto": {
        "type": "object",
        "properties": {
          "number": {
            "type": "string",
            "example": "17",
            "description": "The flat or office number, as typed after the code."
          },
          "floor": {
            "type": "integer",
            "example": 4,
            "nullable": true,
            "description": "The floor of the flat or office. null when not known."
          },
          "kind": {
            "type": "string",
            "enum": [
              "flat",
              "office",
              "shop",
              "stall",
              "kiosk"
            ],
            "description": "flat: a home. office: an office. shop: a shop. stall: a market stall. kiosk: a kiosk."
          }
        },
        "required": [
          "number",
          "floor",
          "kind"
        ]
      },
      "DoorDto": {
        "type": "object",
        "properties": {
          "official_address": {
            "nullable": true,
            "description": "National format, as written by the source.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ]
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ],
            "description": "The level: matched бүртгэлтэй (state register), partial хэсэгчилсэн (public sources), none албан бус (not matched, shown as unofficial)."
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched. Clients must show \"unofficial\"."
          },
          "official_source": {
            "type": "string",
            "example": "zipcode:4364",
            "nullable": true,
            "description": "Where the official address came from, as the register and its record, for example zipcode:4364. null when there is none."
          },
          "official_date": {
            "type": "string",
            "example": "2026-10-18",
            "nullable": true,
            "description": "The date the official address was recorded, YYYY-MM-DD. null when not known."
          },
          "source_date": {
            "type": "string",
            "example": "2026-10-19",
            "nullable": true,
            "description": "Date of the current door or unit row behind the code."
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "description": "The building code, five characters."
          },
          "natural_mn": {
            "type": "string",
            "example": "Сансар А 8",
            "nullable": true,
            "description": "Spoken natural form. null if not known yet."
          },
          "natural_en": {
            "type": "string",
            "example": "Sansar A 8",
            "nullable": true,
            "description": "The English spoken form of the address. null when not known yet."
          },
          "long_mn": {
            "type": "string",
            "example": "Баянзүрх дүүрэг, 8, Сансар А 8",
            "nullable": true,
            "description": "The place in one Mongolian line: the official address with the postal code last when there is one, else the district and the name. null when nothing is known."
          },
          "long_en": {
            "type": "string",
            "example": "Bayanzurkh district, Sansar A 8",
            "nullable": true,
            "description": "The place in one line in English letters. null when unknown. A place that has an official address has none, so no Latin street is made up."
          },
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "description": "[lon, lat] of the entrance, WGS84",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "entrance": {
            "nullable": true,
            "description": "null until the building's entrance method is approved.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/EntranceDto"
              }
            ]
          },
          "unit": {
            "nullable": true,
            "description": "The flat or office typed after the code (\"7QSVX 17\"), if it is on record. null otherwise.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/UnitDto"
              }
            ]
          },
          "confidence": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4,
            "nullable": true,
            "description": "Trust level, 0 to 4. 0 generated, 1 reviewed, 2 confirmed once, 3 confirmed independently, 4 surveyed. null means unknown."
          },
          "confirmations": {
            "type": "integer",
            "minimum": 0,
            "example": 2,
            "description": "Confirmed driver taps for this door since its point last moved. 0 when none."
          },
          "source": {
            "type": "string",
            "example": "osm",
            "description": "Where the row came from, for example osm, overture, generated, a register or a chain's published list. For a building it names the footprint layer. It does not say the address is official: read official_status for that."
          },
          "instructions_mn": {
            "type": "string",
            "nullable": true,
            "description": "How to find the door, in Mongolian, from an approved note. null when there is none."
          },
          "instructions_en": {
            "type": "string",
            "nullable": true,
            "description": "How to find the door, in English. null when there is none."
          },
          "aliases": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Other names for this door. Empty when there are none."
          }
        },
        "required": [
          "official_address",
          "official_status",
          "unofficial",
          "official_source",
          "official_date",
          "source_date",
          "code",
          "natural_mn",
          "natural_en",
          "long_mn",
          "long_en",
          "point",
          "entrance",
          "unit",
          "confidence",
          "confirmations",
          "source",
          "instructions_mn",
          "instructions_en",
          "aliases"
        ]
      },
      "GeocodeNearDto": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "landmark",
              "building",
              "door"
            ],
            "description": "What the landmark is: landmark Газар, building Барилга or door Хаалга. One of landmark Газар, building Барилга, door Хаалга."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Stable id of the landmark the query named."
          },
          "name_mn": {
            "type": "string",
            "nullable": true,
            "example": "Хүннү молл",
            "description": "The landmark's Mongolian name."
          },
          "name_en": {
            "type": "string",
            "nullable": true,
            "example": "Hunnu Mall",
            "description": "The landmark's English name. null when it has none."
          },
          "relation": {
            "type": "string",
            "enum": [
              "north",
              "east",
              "south",
              "west",
              "near",
              "beside"
            ],
            "example": "north",
            "description": "The relation the query said. A side searches within 55 degrees of it; near and beside the whole circle. Mongolian ар (behind) is north and урд (front) south."
          },
          "metres": {
            "type": "number",
            "example": 42.5,
            "description": "Metres from the landmark to the place, 150 at most."
          }
        },
        "required": [
          "kind",
          "id",
          "name_mn",
          "name_en",
          "relation",
          "metres"
        ]
      },
      "GeocodeResultDto": {
        "type": "object",
        "properties": {
          "official_address": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ],
            "description": "The official address of the place. null when it has none."
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ],
            "description": "The level: matched бүртгэлтэй (state register), partial хэсэгчилсэн (public sources), none албан бус (not matched, shown as unofficial)."
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched. Clients must show \"unofficial\"."
          },
          "official_source": {
            "type": "string",
            "nullable": true,
            "description": "Where the official address came from, as the register and its record, for example zipcode:4364. null when there is none."
          },
          "official_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-18",
            "description": "The date the official address was recorded, YYYY-MM-DD. null when not known."
          },
          "official_line": {
            "type": "string",
            "nullable": true,
            "description": "The official address as one Cyrillic line, as GET /v1/door/{code} gives it; null when none is matched.",
            "example": "Баянзүрх дүүрэг, 3-р хороо, Сансар, 8-р байр · 13381-0034"
          },
          "code": {
            "type": "string",
            "nullable": true,
            "example": "7QSVX",
            "description": "Building code. Doors, businesses, landmarks and buildings carry the code of their unit; null when the unit has no code yet, and for a market or a stop."
          },
          "kind": {
            "type": "string",
            "enum": [
              "door",
              "business",
              "building",
              "district",
              "khoroo",
              "area",
              "street",
              "landmark",
              "khashaa"
            ],
            "description": "khashaa: a minted ger plot, in reverse only, without types. Read it with GET /v1/door/{code}; its id is not a GET /v1/address/{id} id. Values, with the word the map shows: door Хаалга, business Байгууллага, building Барилга, district Дүүрэг, khoroo Хороо, area Хороолол, street Гудамж, landmark Газар. khashaa is a ger plot with a code (Хашаа)."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Stable id. Never shown to people as an address."
          },
          "name_mn": {
            "type": "string",
            "nullable": true,
            "example": "Сансар А 8",
            "description": "The Mongolian name. A row whose name is in Latin letters alone is not listed when a row with a Cyrillic name stands at the same place (the same code, or the same kind within 100 m)."
          },
          "name_en": {
            "type": "string",
            "nullable": true,
            "example": "Sansar A 8",
            "description": "The English name, in Latin letters. null when the place has none."
          },
          "long_mn": {
            "type": "string",
            "nullable": true,
            "example": "Баянзүрх дүүрэг, 8, Сансар А 8",
            "description": "The place in one Mongolian line: the official address with the postal code last when there is one, else the district and the name. null when nothing is known."
          },
          "long_en": {
            "type": "string",
            "nullable": true,
            "example": "Bayanzurkh district, Sansar A 8",
            "description": "The place in one line in English letters. null when unknown. A place that has an official address has none, so no Latin street is made up."
          },
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "description": "[lon, lat], WGS84. The entrance for a door.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "confidence": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4,
            "nullable": true,
            "description": "Trust level, 0 to 4. null means unknown; a landmark (a stop, a roundabout) has none measured, so it answers null. Levels: 0 автоматаар байрлуулсан (placed by rule), 1 зурагтай тулгаж шалгасан (checked against imagery), 2 газар дээр нэг удаа баталсан (confirmed once on site), 3 бие даан гурван удаа баталсан (confirmed independently three times), 4 хэмжилтээр баталсан (surveyed)."
          },
          "source": {
            "type": "string",
            "example": "osm",
            "description": "Where the row came from, for example osm, overture, generated, a register or a chain's published list. For a building it names the footprint layer. It does not say the address is official: read official_status for that."
          },
          "source_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-19",
            "description": "The date of the current version of this row, or the register's own date for a door. null: not known."
          },
          "claimed": {
            "type": "boolean",
            "example": true,
            "description": "A business: true when its company has a claim the state register confirmed (the claim form, API 0.9x), so a client can hide the claim link. false when not claimed or the claim is pending. Absent for every other kind."
          },
          "indoor": {
            "type": "object",
            "additionalProperties": true,
            "example": {
              "venue_id": "0198d1c0-0000-7000-8000-000000000001",
              "category": "airport",
              "levels": [
                0,
                1
              ],
              "units": [
                {
                  "unit_id": "0198d1c0-0000-7000-8000-000000000002",
                  "level": 1,
                  "name_mn": "Мэдээллийн төв",
                  "number": null,
                  "category": "service",
                  "source": "dock:survey",
                  "confidence": 2
                }
              ]
            },
            "description": "A building that has an indoor map: venue_id (GET /v1/venue/{id}), category (what the venue is: airport, mall, ...; a client says \"Нисэх буудал\" instead of \"Барилга\"), levels (floor numbers, lowest first) and units, the units the query names (a unit name or its number as a whole word) with level, number, source and confidence (up to 5). Absent for every other row."
          },
          "khoroo": {
            "type": "integer",
            "nullable": true,
            "example": 8,
            "description": "A business, landmark or street: the khoroo number (for a street, where its point stands) its point stands in, from the khoroo polygons; null when none covers it. With the district it tells two branches of one name apart. Absent for every other kind."
          },
          "restricted": {
            "type": "boolean",
            "example": false,
            "description": "A business: true when its point lies inside a restricted site (PLAN 20.2), so a client hides the claim link and any edit. Absent for every other kind."
          },
          "category": {
            "type": "string",
            "nullable": true,
            "example": "pharmacy",
            "description": "A business or landmark: its map category, the one GET /v1/nearby gives (pharmacy, bank, fuel, ...). null for a door, a building and any place without one."
          },
          "building_type": {
            "type": "string",
            "nullable": true,
            "example": "apartment",
            "enum": [
              "apartment",
              "ger_house",
              "commercial",
              "public",
              "industrial",
              "garage",
              "other"
            ],
            "description": "A building: what it is, from the register or the map (apartment, ger_house, commercial, public, industrial, garage, other). null when the building has no type yet. Absent for every other kind."
          },
          "name_is_kind_word": {
            "type": "boolean",
            "nullable": true,
            "example": false,
            "description": "A building: true when its whole name is only a kind word (Үсчин, Дэлгүүр), so a client shows it as a kind and not as a title. null when not checked. Absent for every other kind."
          },
          "poi_category": {
            "type": "string",
            "nullable": true,
            "example": "shop=hairdresser",
            "description": "A building: the OSM category of the one POI standing in its footprint, so a card can say what the place is. null when unknown. Never guessed from a name. Absent for every other kind."
          },
          "building_levels": {
            "type": "integer",
            "nullable": true,
            "example": 25,
            "description": "A building: its number of storeys (OSM building:levels), so a card can tell a tower from the podium that shares its name (\"25 давхар\" and \"4 давхар\"). null when unknown. Absent for every other kind."
          },
          "host": {
            "type": "string",
            "nullable": true,
            "example": "T87ZW",
            "description": "A building: when it is a part of another building (core.building_part), the code of the host, the same value GET /v1/door answers as host, so a client shows the part under its host. null for a host or a stand-alone building. Absent for every other kind."
          },
          "poi_names": {
            "example": [
              "Номин"
            ],
            "description": "A building: up to 5 company names registered at it (state entity register match only, never an unregistered POI). [] when none. Absent for every other kind.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "matched_name": {
            "type": "string",
            "example": "Shangri-La зочид буудлын зоогийн газар",
            "description": "A building: the name the query matched when the row title is another text (an address title over the building's own name), so a client can say why the row is there. Absent when the title already holds the query and for every other kind."
          },
          "score": {
            "type": "number",
            "example": 1.136,
            "description": "Match score. Higher is better; compare only with results of the same layer in one response."
          },
          "layer": {
            "type": "number",
            "enum": [
              1,
              2,
              3
            ],
            "example": 1,
            "description": "1: the name or address matched the words typed. 2: the place description matched the meaning (PLAN.md 7 layer 2), listed after every layer 1 result, except around a named landmark (see near). 3: around a named landmark, layer 2's best places read again side by side with the query by a reranking model (PLAN.md 7 layer 3); score is that model's, 0 to 1. When the reranker is slow or down, those stay layer 2."
          },
          "near": {
            "nullable": true,
            "description": "Set for a place found around the landmark a query named (\"Хүннү моллын ард\", \"east of Max Mall\"): those come first, ranked on the meaning of the query (layer 3, or layer 2 without the reranker), or by distance when it says nothing more (layer 1). null for every other result.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/GeocodeNearDto"
              }
            ]
          },
          "lines": {
            "nullable": true,
            "example": [
              "М:1",
              "Ч:7",
              "Ч:41"
            ],
            "description": "A bus stop: the city bus lines that call at it, as GET /v1/nearby gives them. null for every other place and for a stop the capital's public transport open data (opendata.ubcard.mn, CC0 1.0) lists none at.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "floor": {
            "type": "integer",
            "nullable": true,
            "example": 12,
            "description": "A company from a building's directory: its floor, from the legal address in the state entity register. On a building or khashaa row with a code, the N of \"N давхар\" in the query. null when not said, and for every other place."
          },
          "flat": {
            "type": "string",
            "nullable": true,
            "example": "1204",
            "description": "A company from a building's directory: its flat or office number (N тоот). On a building or khashaa row with a code, the N of \"N тоот\" in the query. null when not said."
          }
        },
        "required": [
          "official_address",
          "official_status",
          "unofficial",
          "official_source",
          "official_date",
          "official_line",
          "code",
          "kind",
          "id",
          "name_mn",
          "name_en",
          "long_mn",
          "long_en",
          "point",
          "confidence",
          "source",
          "source_date",
          "category",
          "score",
          "layer",
          "near",
          "lines",
          "floor",
          "flat"
        ]
      },
      "GeocodeUnitDto": {
        "type": "object",
        "properties": {
          "official_address": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ],
            "description": "The official address of the building or ger plot the code names."
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ],
            "description": "The level: matched бүртгэлтэй (state register), partial хэсэгчилсэн (public sources), none албан бус (not matched, shown as unofficial)."
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched. Clients must show \"unofficial\"."
          },
          "official_source": {
            "type": "string",
            "nullable": true,
            "description": "Where the official address came from, as the register and its record, for example zipcode:4364. null when there is none."
          },
          "official_date": {
            "type": "string",
            "nullable": true,
            "description": "The date the official address was recorded, YYYY-MM-DD. null when not known."
          },
          "source_date": {
            "type": "string",
            "example": "2026-10-19",
            "nullable": true,
            "description": "Date of the current door or unit row behind the code."
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "description": "The code that was in the query."
          },
          "kind": {
            "type": "string",
            "enum": [
              "building",
              "khashaa"
            ],
            "description": "building Барилга: a building with a code. khashaa Хашаа: a ger plot with a code."
          },
          "source": {
            "type": "string",
            "nullable": true,
            "example": "state",
            "description": "Where the unit row came from. null when unknown."
          },
          "confidence": {
            "type": "number",
            "nullable": true,
            "example": 2,
            "description": "How sure dock is of the building row, 0 to 4; lower for a state-only building. null for a khashaa or when unknown."
          },
          "official_line": {
            "type": "string",
            "nullable": true,
            "example": "Баянзүрх дүүрэг, 3-р хороо, Сансар, 8-р байр · 13381-0034",
            "description": "The official address as one Cyrillic line, postal code last. null when nothing is known."
          },
          "area_line": {
            "type": "string",
            "nullable": true,
            "example": "Хан-Уул дүүрэг, 1-р хороо",
            "description": "Where the point lies by the district and khoroo borders. Set when the address is not matched, and when a matched address names another district or soum than the point lies in (the register text stays in official_line). Unofficial, never an address. null otherwise."
          },
          "building_type": {
            "type": "string",
            "nullable": true,
            "example": "public",
            "description": "What the building is: apartment, ger_house, commercial, public, industrial, garage or other. null for a khashaa or when the building has no type yet; never guessed."
          },
          "opening_hours": {
            "type": "string",
            "nullable": true,
            "example": "Mo-Fr 09:00-18:00",
            "description": "The OpenStreetMap opening_hours tag of the landmark inside the building, as written. A tag can be old: show it as \"hours from OpenStreetMap\". null for a khashaa or when there is none; never guessed."
          },
          "hours_source": {
            "type": "string",
            "nullable": true,
            "example": "osm",
            "description": "Where opening_hours came from. null when opening_hours is null."
          },
          "building_levels": {
            "type": "number",
            "nullable": true,
            "example": 12,
            "description": "Floors above ground from the building record. null for a khashaa or when the building has none; never guessed."
          },
          "wheelchair": {
            "type": "string",
            "nullable": true,
            "enum": [
              "yes",
              "limited",
              "no"
            ],
            "example": "limited",
            "description": "Wheelchair access as OSM mappers recorded it for this building. null is unknown, never step free; only yes, limited and no are answers."
          },
          "outline": {
            "type": "object",
            "nullable": true,
            "example": {
              "type": "Polygon",
              "coordinates": [
                [
                  [
                    106.9203,
                    47.9135
                  ],
                  [
                    106.9215,
                    47.9135
                  ],
                  [
                    106.9215,
                    47.9122
                  ],
                  [
                    106.9203,
                    47.9135
                  ]
                ]
              ]
            },
            "description": "The building's whole footprint, GeoJSON Polygon or MultiPolygon in WGS84, simplified to about 0.5 m, 6 decimals. Draw the selection from this, not from map tiles, which cut a large building at tile edges. A khashaa answers its yard polygon. null when the unit has no polygon."
          },
          "parts": {
            "example": [
              {
                "code": "K0SR9",
                "name": "C блок",
                "levels": 35
              }
            ],
            "description": "Buildings that lie mostly inside this one (over 60 % of their area). Each keeps its own code, and that code opens this building. levels is the own floor count of the part, null when unknown, so two parts with one name can be told apart. name is null when the part has only a Latin name (the map reads Mongolian), the code and levels name it. Empty when none.",
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "host": {
            "type": "string",
            "nullable": true,
            "example": "T87ZW",
            "description": "When this code's building is a part of another, the host's code; open that code for the page. null for a host or a stand-alone building."
          },
          "complex_name": {
            "type": "string",
            "nullable": true,
            "example": "Нарны хороолол 3",
            "description": "The complex the building belongs to, from the official register. Not the building's own name. null when none."
          },
          "photo": {
            "type": "object",
            "nullable": true,
            "example": {
              "url": "https://upload.wikimedia.org/wikipedia/commons/a/a1/Shangri-La.jpg",
              "credit": "https://commons.wikimedia.org/wiki/File:Shangri-La.jpg",
              "license": "CC BY-SA 4.0",
              "source": "commons",
              "author": "A. Author"
            },
            "description": "One openly licensed Commons photo of the building, as GET /v1/address/{id} gives it: { url, credit, license, source, author? }. null when none. Show author, then credit and license."
          },
          "name_mn": {
            "type": "string",
            "nullable": true,
            "description": "The Mongolian name of the building or plot. null when it has none."
          },
          "name_en": {
            "type": "string",
            "nullable": true,
            "description": "The English name. null when it has none."
          },
          "point": {
            "example": [
              106.9177,
              47.9186
            ],
            "description": "[lon, lat] of a point inside the footprint, WGS84",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "floor": {
            "type": "integer",
            "nullable": true,
            "example": 12,
            "description": "N in \"N давхар\", null when not said."
          },
          "flat": {
            "type": "string",
            "nullable": true,
            "example": "1204",
            "description": "N in \"N тоот\", null when not said."
          },
          "venue_id": {
            "type": "string",
            "example": "0198d1c0-0000-7000-8000-000000000001",
            "description": "The building holds an indoor map: its venue id (GET /v1/venue/{id}). Absent when it holds none."
          }
        },
        "required": [
          "official_address",
          "official_status",
          "unofficial",
          "official_source",
          "official_date",
          "source_date",
          "code",
          "kind",
          "source",
          "confidence",
          "official_line",
          "area_line",
          "building_type",
          "opening_hours",
          "hours_source",
          "building_levels",
          "wheelchair",
          "outline",
          "parts",
          "host",
          "complex_name",
          "photo",
          "name_mn",
          "name_en",
          "point",
          "floor",
          "flat"
        ]
      },
      "GeocodeDto": {
        "type": "object",
        "properties": {
          "results": {
            "description": "Best first. Empty when nothing matches.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GeocodeResultDto"
            }
          },
          "unit": {
            "nullable": true,
            "description": "Set when the whole query is a unit code of a building or khashaa, alone (\"7QSVX\") or spoken (\"7QSVX, 12 давхар, 1204 тоот\"): the unit card, as GET /v1/door/{code} answers it, with floor and flat. results still hold the name matches of the same text. null for every other query.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/GeocodeUnitDto"
              }
            ]
          },
          "indoor_units": {
            "description": "The units inside a building with an indoor map that the query names (a unit name, or its number as a whole word), each as its own answer: venue_id, venue_name_mn, code (the building code, null when the building has none), level (floor number), name_mn, number, category, point [lon, lat] (a point inside the unit, null when none), source and confidence. Up to 5. Absent when no unit is named. Fixtures are never listed.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "results",
          "unit"
        ]
      },
      "ReverseResultDto": {
        "type": "object",
        "properties": {
          "official_address": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ],
            "description": "The state's official address, in Cyrillic: city or aimag, district, khoroo, street or microdistrict, building, with the postal code. null when the place has no official address."
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ],
            "description": "The level: matched бүртгэлтэй (state register), partial хэсэгчилсэн (public sources), none албан бус (not matched, shown as unofficial)."
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched. Clients must show \"unofficial\"."
          },
          "official_source": {
            "type": "string",
            "nullable": true,
            "description": "Where the official address came from, as the register and its record, for example zipcode:4364. null when there is none."
          },
          "official_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-18",
            "description": "The date the official address was recorded, YYYY-MM-DD. null when not known."
          },
          "official_line": {
            "type": "string",
            "nullable": true,
            "description": "The official address as one Cyrillic line, as GET /v1/door/{code} gives it; null when none is matched.",
            "example": "Баянзүрх дүүрэг, 3-р хороо, Сансар, 8-р байр · 13381-0034"
          },
          "code": {
            "type": "string",
            "nullable": true,
            "example": "7QSVX",
            "description": "Building code. Doors, businesses, landmarks and buildings carry the code of their unit; null when the unit has no code yet, and for a market or a stop."
          },
          "kind": {
            "type": "string",
            "enum": [
              "door",
              "business",
              "building",
              "district",
              "khoroo",
              "area",
              "street",
              "landmark",
              "khashaa"
            ],
            "description": "khashaa: a minted ger plot, in reverse only, without types. Read it with GET /v1/door/{code}; its id is not a GET /v1/address/{id} id. Values, with the word the map shows: door Хаалга, business Байгууллага, building Барилга, district Дүүрэг, khoroo Хороо, area Хороолол, street Гудамж, landmark Газар. khashaa is a ger plot with a code (Хашаа)."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Stable id. Never shown to people as an address."
          },
          "name_mn": {
            "type": "string",
            "nullable": true,
            "example": "Сансар А 8",
            "description": "The Mongolian name. A row whose name is in Latin letters alone is not listed when a row with a Cyrillic name stands at the same place (the same code, or the same kind within 100 m)."
          },
          "name_en": {
            "type": "string",
            "nullable": true,
            "example": "Sansar A 8",
            "description": "The English name, in Latin letters. null when the place has none."
          },
          "long_mn": {
            "type": "string",
            "nullable": true,
            "example": "Баянзүрх дүүрэг, 8, Сансар А 8",
            "description": "The place in one Mongolian line: the official address with the postal code last when there is one, else the district and the name. null when nothing is known."
          },
          "long_en": {
            "type": "string",
            "nullable": true,
            "example": "Bayanzurkh district, Sansar A 8",
            "description": "The place in one line in English letters. null when unknown. A place that has an official address has none, so no Latin street is made up."
          },
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "description": "[lon, lat], WGS84. The entrance for a door.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "confidence": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4,
            "nullable": true,
            "description": "Trust level, 0 to 4. null means unknown; a landmark (a stop, a roundabout) has none measured, so it answers null. Levels: 0 автоматаар байрлуулсан (placed by rule), 1 зурагтай тулгаж шалгасан (checked against imagery), 2 газар дээр нэг удаа баталсан (confirmed once on site), 3 бие даан гурван удаа баталсан (confirmed independently three times), 4 хэмжилтээр баталсан (surveyed)."
          },
          "source": {
            "type": "string",
            "example": "osm",
            "description": "Where the row came from, for example osm, overture, generated, a register or a chain's published list. For a building it names the footprint layer. It does not say the address is official: read official_status for that."
          },
          "source_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-19",
            "description": "The date of the current version of this row, or the register's own date for a door. null: not known."
          },
          "claimed": {
            "type": "boolean",
            "example": true,
            "description": "A business: true when its company has a claim the state register confirmed (the claim form, API 0.9x), so a client can hide the claim link. false when not claimed or the claim is pending. Absent for every other kind."
          },
          "indoor": {
            "type": "object",
            "additionalProperties": true,
            "example": {
              "venue_id": "0198d1c0-0000-7000-8000-000000000001",
              "category": "airport",
              "levels": [
                0,
                1
              ],
              "units": [
                {
                  "unit_id": "0198d1c0-0000-7000-8000-000000000002",
                  "level": 1,
                  "name_mn": "Мэдээллийн төв",
                  "number": null,
                  "category": "service",
                  "source": "dock:survey",
                  "confidence": 2
                }
              ]
            },
            "description": "A building that has an indoor map: venue_id (GET /v1/venue/{id}), category (what the venue is: airport, mall, ...; a client says \"Нисэх буудал\" instead of \"Барилга\"), levels (floor numbers, lowest first) and units, the units the query names (a unit name or its number as a whole word) with level, number, source and confidence (up to 5). Absent for every other row."
          },
          "khoroo": {
            "type": "integer",
            "nullable": true,
            "example": 8,
            "description": "A business, landmark or street: the khoroo number (for a street, where its point stands) its point stands in, from the khoroo polygons; null when none covers it. With the district it tells two branches of one name apart. Absent for every other kind."
          },
          "restricted": {
            "type": "boolean",
            "example": false,
            "description": "A business: true when its point lies inside a restricted site (PLAN 20.2), so a client hides the claim link and any edit. Absent for every other kind."
          },
          "category": {
            "type": "string",
            "nullable": true,
            "example": "pharmacy",
            "description": "A business or landmark: its map category, the one GET /v1/nearby gives (pharmacy, bank, fuel, ...). null for a door, a building and any place without one."
          },
          "building_type": {
            "type": "string",
            "nullable": true,
            "example": "apartment",
            "enum": [
              "apartment",
              "ger_house",
              "commercial",
              "public",
              "industrial",
              "garage",
              "other"
            ],
            "description": "A building: what it is, from the register or the map (apartment, ger_house, commercial, public, industrial, garage, other). null when the building has no type yet. Absent for every other kind."
          },
          "name_is_kind_word": {
            "type": "boolean",
            "nullable": true,
            "example": false,
            "description": "A building: true when its whole name is only a kind word (Үсчин, Дэлгүүр), so a client shows it as a kind and not as a title. null when not checked. Absent for every other kind."
          },
          "poi_category": {
            "type": "string",
            "nullable": true,
            "example": "shop=hairdresser",
            "description": "A building: the OSM category of the one POI standing in its footprint, so a card can say what the place is. null when unknown. Never guessed from a name. Absent for every other kind."
          },
          "building_levels": {
            "type": "integer",
            "nullable": true,
            "example": 25,
            "description": "A building: its number of storeys (OSM building:levels), so a card can tell a tower from the podium that shares its name (\"25 давхар\" and \"4 давхар\"). null when unknown. Absent for every other kind."
          },
          "host": {
            "type": "string",
            "nullable": true,
            "example": "T87ZW",
            "description": "A building: when it is a part of another building (core.building_part), the code of the host, the same value GET /v1/door answers as host, so a client shows the part under its host. null for a host or a stand-alone building. Absent for every other kind."
          },
          "poi_names": {
            "example": [
              "Номин"
            ],
            "description": "A building: up to 5 company names registered at it (state entity register match only, never an unregistered POI). [] when none. Absent for every other kind.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "matched_name": {
            "type": "string",
            "example": "Shangri-La зочид буудлын зоогийн газар",
            "description": "A building: the name the query matched when the row title is another text (an address title over the building's own name), so a client can say why the row is there. Absent when the title already holds the query and for every other kind."
          },
          "distance_m": {
            "type": "number",
            "example": 4.2,
            "description": "Metres from the query point. 0 means the point is inside."
          },
          "lines": {
            "nullable": true,
            "example": [
              "М:1",
              "Ч:7",
              "Ч:41"
            ],
            "description": "A bus stop: the city bus lines that call at it, as GET /v1/nearby gives them. null for every other place and for a stop the capital's public transport open data (opendata.ubcard.mn, CC0 1.0) lists none at.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "official_address",
          "official_status",
          "unofficial",
          "official_source",
          "official_date",
          "official_line",
          "code",
          "kind",
          "id",
          "name_mn",
          "name_en",
          "long_mn",
          "long_en",
          "point",
          "confidence",
          "source",
          "source_date",
          "category",
          "distance_m",
          "lines"
        ]
      },
      "ReverseDto": {
        "type": "object",
        "properties": {
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "The point asked from, [lon, lat]."
          },
          "district_mn": {
            "type": "string",
            "nullable": true,
            "example": "Баянзүрх",
            "description": "The district (дүүрэг) of the point, in Mongolian. null when no district covers it."
          },
          "district_en": {
            "type": "string",
            "nullable": true,
            "example": "Bayanzurkh",
            "description": "The district of the point, in English letters. null when no district covers it."
          },
          "khoroo": {
            "type": "integer",
            "nullable": true,
            "example": 3,
            "description": "null when no khoroo polygon covers the point. Never guessed."
          },
          "soum_mn": {
            "type": "string",
            "nullable": true,
            "example": "Сэргэлэн",
            "description": "The soum covering the point (OSM boundaries, API 0.104.0); null when no polygon covers it. Never guessed."
          },
          "aimag_mn": {
            "type": "string",
            "nullable": true,
            "example": "Төв",
            "description": "The aimag covering the point (OSM boundaries, API 0.104.0); null when no polygon covers it."
          },
          "restricted": {
            "type": "boolean",
            "example": false,
            "description": "true when the point itself lies inside a restricted site (PLAN 20.2): results is then empty, and a client hides the claim link and any edit on the card it opens."
          },
          "results": {
            "description": "Nearest first, within radius.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReverseResultDto"
            }
          }
        },
        "required": [
          "point",
          "district_mn",
          "district_en",
          "khoroo",
          "soum_mn",
          "aimag_mn",
          "restricted",
          "results"
        ]
      },
      "NearbyResultDto": {
        "type": "object",
        "properties": {
          "official_address": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ],
            "description": "The state's official address, in Cyrillic: city or aimag, district, khoroo, street or microdistrict, building, with the postal code. null when the place has no official address."
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ],
            "description": "The level: matched бүртгэлтэй (state register), partial хэсэгчилсэн (public sources), none албан бус (not matched, shown as unofficial)."
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched. Clients must show \"unofficial\"."
          },
          "official_source": {
            "type": "string",
            "nullable": true,
            "description": "Where the official address came from, as the register and its record, for example zipcode:4364. null when there is none."
          },
          "official_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-18",
            "description": "The date the official address was recorded, YYYY-MM-DD. null when not known."
          },
          "official_line": {
            "type": "string",
            "nullable": true,
            "description": "The official address as one Cyrillic line, as GET /v1/door/{code} gives it; null when none is matched.",
            "example": "Баянзүрх дүүрэг, 3-р хороо, Сансар, 8-р байр · 13381-0034"
          },
          "code": {
            "type": "string",
            "nullable": true,
            "example": "7QSVX",
            "description": "Unit code of the place: a door, a business through its door, or the building or хашаа a store or company stands in. null when none is minted yet: show \"код алга\" and the official address, which is the building's it stands in, or none."
          },
          "kind": {
            "type": "string",
            "enum": [
              "door",
              "business",
              "building",
              "district",
              "khoroo",
              "area",
              "street",
              "landmark",
              "khashaa"
            ],
            "description": "khashaa: a minted ger plot, in reverse only, without types. Read it with GET /v1/door/{code}; its id is not a GET /v1/address/{id} id. Values, with the word the map shows: door Хаалга, business Байгууллага, building Барилга, district Дүүрэг, khoroo Хороо, area Хороолол, street Гудамж, landmark Газар. khashaa is a ger plot with a code (Хашаа)."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Stable id. Never shown to people as an address."
          },
          "name_mn": {
            "type": "string",
            "nullable": true,
            "example": "Сансар А 8",
            "description": "The Mongolian name. A row whose name is in Latin letters alone is not listed when a row with a Cyrillic name stands at the same place (the same code, or the same kind within 100 m)."
          },
          "name_en": {
            "type": "string",
            "nullable": true,
            "example": "Sansar A 8",
            "description": "The English name, in Latin letters. null when the place has none."
          },
          "long_mn": {
            "type": "string",
            "nullable": true,
            "example": "Баянзүрх дүүрэг, 8, Сансар А 8",
            "description": "The place in one Mongolian line: the official address with the postal code last when there is one, else the district and the name. null when nothing is known."
          },
          "long_en": {
            "type": "string",
            "nullable": true,
            "example": "Bayanzurkh district, Sansar A 8",
            "description": "The place in one line in English letters. null when unknown. A place that has an official address has none, so no Latin street is made up."
          },
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "description": "[lon, lat], WGS84. The entrance for a door.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "confidence": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4,
            "nullable": true,
            "description": "Trust level, 0 to 4. null means unknown; a landmark (a stop, a roundabout) has none measured, so it answers null. Levels: 0 автоматаар байрлуулсан (placed by rule), 1 зурагтай тулгаж шалгасан (checked against imagery), 2 газар дээр нэг удаа баталсан (confirmed once on site), 3 бие даан гурван удаа баталсан (confirmed independently three times), 4 хэмжилтээр баталсан (surveyed)."
          },
          "source": {
            "type": "string",
            "example": "osm",
            "description": "Where the row came from, for example osm, overture, generated, a register or a chain's published list. For a building it names the footprint layer. It does not say the address is official: read official_status for that."
          },
          "source_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-19",
            "description": "The date of the current version of this row, or the register's own date for a door. null: not known."
          },
          "claimed": {
            "type": "boolean",
            "example": true,
            "description": "A business: true when its company has a claim the state register confirmed (the claim form, API 0.9x), so a client can hide the claim link. false when not claimed or the claim is pending. Absent for every other kind."
          },
          "indoor": {
            "type": "object",
            "additionalProperties": true,
            "example": {
              "venue_id": "0198d1c0-0000-7000-8000-000000000001",
              "category": "airport",
              "levels": [
                0,
                1
              ],
              "units": [
                {
                  "unit_id": "0198d1c0-0000-7000-8000-000000000002",
                  "level": 1,
                  "name_mn": "Мэдээллийн төв",
                  "number": null,
                  "category": "service",
                  "source": "dock:survey",
                  "confidence": 2
                }
              ]
            },
            "description": "A building that has an indoor map: venue_id (GET /v1/venue/{id}), category (what the venue is: airport, mall, ...; a client says \"Нисэх буудал\" instead of \"Барилга\"), levels (floor numbers, lowest first) and units, the units the query names (a unit name or its number as a whole word) with level, number, source and confidence (up to 5). Absent for every other row."
          },
          "khoroo": {
            "type": "integer",
            "nullable": true,
            "example": 8,
            "description": "A business, landmark or street: the khoroo number (for a street, where its point stands) its point stands in, from the khoroo polygons; null when none covers it. With the district it tells two branches of one name apart. Absent for every other kind."
          },
          "restricted": {
            "type": "boolean",
            "example": false,
            "description": "A business: true when its point lies inside a restricted site (PLAN 20.2), so a client hides the claim link and any edit. Absent for every other kind."
          },
          "category": {
            "type": "string",
            "enum": [
              "atm",
              "bank",
              "bridge",
              "cafe",
              "car_wash",
              "culture",
              "embassy",
              "fuel",
              "government",
              "hospital",
              "hotel",
              "kindergarten",
              "mall",
              "market",
              "monument",
              "office",
              "park",
              "pharmacy",
              "religion",
              "restaurant",
              "school",
              "shop",
              "sport",
              "station",
              "stop",
              "university"
            ],
            "example": "pharmacy",
            "description": "The map category, as the place icon."
          },
          "distance_m": {
            "type": "number",
            "example": 120.4,
            "description": "Metres from the query point."
          },
          "area_line": {
            "type": "string",
            "nullable": true,
            "example": "Дархан-Уул аймаг, Дархан сум",
            "description": "Where the place stands, from its point: district or сум (and aimag outside the capital), khoroo when one covers it. Absent for kinds other than business and landmark; null when no polygon covers the point. Unofficial: it is the area, not the place's own address."
          },
          "photo": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Only with photo=1: { url, credit, license, source, author? } as on GET /v1/address/{id}; null when none."
          },
          "lines": {
            "nullable": true,
            "example": [
              "М:1",
              "Ч:7",
              "Ч:41"
            ],
            "description": "The city bus lines that call at this stop, as the bus shows them, letter then number. Source: the capital's public transport open data (opendata.ubcard.mn, CC0 1.0). null when that data lists none here.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "floor": {
            "type": "integer",
            "nullable": true,
            "example": 12,
            "description": "A registered company from a building's directory: its floor, from the legal address in the state entity register. null when the register does not say, and for every other place. The code is its building's."
          },
          "flat": {
            "type": "string",
            "nullable": true,
            "example": "1204",
            "description": "A company's flat or office number from the same address. null when the register does not say."
          },
          "opening_hours": {
            "type": "string",
            "nullable": true,
            "example": "Mo-Fr 09:00-20:00; Sa 10:00-18:00",
            "description": "The OpenStreetMap opening_hours tag, as written. A tag can be old: show it as \"hours from OpenStreetMap\". null when the source has none."
          },
          "hours_source": {
            "type": "string",
            "nullable": true,
            "example": "osm",
            "description": "Where opening_hours came from. null when opening_hours is null."
          },
          "open_now": {
            "type": "boolean",
            "nullable": true,
            "example": true,
            "description": "Open at this moment in Ulaanbaatar time, read from a plain opening_hours tag (24/7 or weekly rules). From OpenStreetMap, may be old. null when there is no tag or it is not plain (sunrise, holidays, free text): unknown, never a guess."
          },
          "open_until": {
            "type": "string",
            "nullable": true,
            "example": "21:00",
            "description": "When the place closes today, HH:MM in Ulaanbaatar time, while open_now is true. null when closed, unknown, or open 24/7."
          },
          "opens_at": {
            "type": "string",
            "nullable": true,
            "example": "10:00",
            "description": "When a closed place opens later today, HH:MM in Ulaanbaatar time. null when open, unknown, or nothing starts later today (a place that opens tomorrow is not guessed)."
          }
        },
        "required": [
          "official_address",
          "official_status",
          "unofficial",
          "official_source",
          "official_date",
          "official_line",
          "code",
          "kind",
          "id",
          "name_mn",
          "name_en",
          "long_mn",
          "long_en",
          "point",
          "confidence",
          "source",
          "source_date",
          "category",
          "distance_m",
          "lines",
          "floor",
          "flat",
          "opening_hours",
          "hours_source",
          "open_now",
          "open_until",
          "opens_at"
        ]
      },
      "NearbyDto": {
        "type": "object",
        "properties": {
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "The point asked from, [lon, lat]."
          },
          "results": {
            "description": "Nearest first, within radius. Empty when none.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NearbyResultDto"
            }
          },
          "more": {
            "type": "integer",
            "minimum": 0,
            "example": 14,
            "description": "How many more places of these categories lie within radius past limit. 0 when results holds them all."
          },
          "hours_unknown": {
            "type": "integer",
            "minimum": 0,
            "example": 6,
            "description": "Only with open=1: how many of the nearest 20 places have no readable hours (open_now null). They are not in results. Do not show this count as words: a place with unknown hours is simply not listed."
          }
        },
        "required": [
          "point",
          "results",
          "more"
        ]
      },
      "ParentsDto": {
        "type": "object",
        "properties": {
          "door": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "The door of a business. null for a door."
          },
          "building": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "The building the door is in. null when none."
          },
          "plot": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Khashaa (plot)."
          },
          "area": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "The area (хороолол) the door is in. null when none."
          },
          "street": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "The street the door is on. null when none."
          },
          "khoroo": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "null when no khoroo polygon covers the door. Never guessed."
          },
          "district": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "The district the door is in. null when none."
          }
        },
        "required": [
          "door",
          "building",
          "plot",
          "area",
          "street",
          "khoroo",
          "district"
        ]
      },
      "AddressDto": {
        "type": "object",
        "properties": {
          "official_address": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ],
            "description": "The official address of the place. null when it has none."
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ],
            "description": "The level: matched бүртгэлтэй (state register), partial хэсэгчилсэн (public sources), none албан бус (not matched, shown as unofficial)."
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched. Clients must show \"unofficial\"."
          },
          "official_source": {
            "type": "string",
            "nullable": true,
            "description": "Where the official address came from, as the register and its record, for example zipcode:4364. null when there is none."
          },
          "official_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-18",
            "description": "The date the official address was recorded, YYYY-MM-DD. null when not known."
          },
          "official_line": {
            "type": "string",
            "nullable": true,
            "description": "The official address as one Cyrillic line, as GET /v1/door/{code} gives it; null when none is matched.",
            "example": "Баянзүрх дүүрэг, 3-р хороо, Сансар, 8-р байр · 13381-0034"
          },
          "code": {
            "type": "string",
            "nullable": true,
            "example": "7QSVX",
            "description": "Building code. Doors, businesses, landmarks and buildings carry the code of their unit; null when the unit has no code yet, and for a market or a stop."
          },
          "kind": {
            "type": "string",
            "enum": [
              "door",
              "business",
              "building",
              "district",
              "khoroo",
              "area",
              "street",
              "landmark",
              "khashaa"
            ],
            "description": "khashaa: a minted ger plot, in reverse only, without types. Read it with GET /v1/door/{code}; its id is not a GET /v1/address/{id} id. Values, with the word the map shows: door Хаалга, business Байгууллага, building Барилга, district Дүүрэг, khoroo Хороо, area Хороолол, street Гудамж, landmark Газар. khashaa is a ger plot with a code (Хашаа)."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Stable id. Never shown to people as an address."
          },
          "name_mn": {
            "type": "string",
            "nullable": true,
            "example": "Сансар А 8",
            "description": "The Mongolian name. A row whose name is in Latin letters alone is not listed when a row with a Cyrillic name stands at the same place (the same code, or the same kind within 100 m)."
          },
          "name_en": {
            "type": "string",
            "nullable": true,
            "example": "Sansar A 8",
            "description": "The English name, in Latin letters. null when the place has none."
          },
          "long_mn": {
            "type": "string",
            "nullable": true,
            "example": "Баянзүрх дүүрэг, 8, Сансар А 8",
            "description": "The place in one Mongolian line: the official address with the postal code last when there is one, else the district and the name. null when nothing is known."
          },
          "long_en": {
            "type": "string",
            "nullable": true,
            "example": "Bayanzurkh district, Sansar A 8",
            "description": "The place in one line in English letters. null when unknown. A place that has an official address has none, so no Latin street is made up."
          },
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "description": "[lon, lat], WGS84. The entrance for a door.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "confidence": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4,
            "nullable": true,
            "description": "Trust level, 0 to 4. null means unknown; a landmark (a stop, a roundabout) has none measured, so it answers null. Levels: 0 автоматаар байрлуулсан (placed by rule), 1 зурагтай тулгаж шалгасан (checked against imagery), 2 газар дээр нэг удаа баталсан (confirmed once on site), 3 бие даан гурван удаа баталсан (confirmed independently three times), 4 хэмжилтээр баталсан (surveyed)."
          },
          "source": {
            "type": "string",
            "example": "osm",
            "description": "Where the row came from, for example osm, overture, generated, a register or a chain's published list. For a building it names the footprint layer. It does not say the address is official: read official_status for that."
          },
          "source_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-19",
            "description": "The date of the current version of this row, or the register's own date for a door. null: not known."
          },
          "claimed": {
            "type": "boolean",
            "example": true,
            "description": "A business: true when its company has a claim the state register confirmed (the claim form, API 0.9x), so a client can hide the claim link. false when not claimed or the claim is pending. Absent for every other kind."
          },
          "indoor": {
            "type": "object",
            "additionalProperties": true,
            "example": {
              "venue_id": "0198d1c0-0000-7000-8000-000000000001",
              "category": "airport",
              "levels": [
                0,
                1
              ],
              "units": [
                {
                  "unit_id": "0198d1c0-0000-7000-8000-000000000002",
                  "level": 1,
                  "name_mn": "Мэдээллийн төв",
                  "number": null,
                  "category": "service",
                  "source": "dock:survey",
                  "confidence": 2
                }
              ]
            },
            "description": "A building that has an indoor map: venue_id (GET /v1/venue/{id}), category (what the venue is: airport, mall, ...; a client says \"Нисэх буудал\" instead of \"Барилга\"), levels (floor numbers, lowest first) and units, the units the query names (a unit name or its number as a whole word) with level, number, source and confidence (up to 5). Absent for every other row."
          },
          "khoroo": {
            "type": "integer",
            "nullable": true,
            "example": 8,
            "description": "A business, landmark or street: the khoroo number (for a street, where its point stands) its point stands in, from the khoroo polygons; null when none covers it. With the district it tells two branches of one name apart. Absent for every other kind."
          },
          "restricted": {
            "type": "boolean",
            "example": false,
            "description": "A business: true when its point lies inside a restricted site (PLAN 20.2), so a client hides the claim link and any edit. Absent for every other kind."
          },
          "parents": {
            "nullable": true,
            "description": "Doors and businesses; a khoroo carries its district only; null for every other kind.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/ParentsDto"
              }
            ]
          },
          "lines": {
            "nullable": true,
            "example": [
              "М:1",
              "Ч:7",
              "Ч:41"
            ],
            "description": "A bus stop: the city bus lines that call at it, as GET /v1/nearby gives them. null for every other place and for a stop the capital's public transport open data (opendata.ubcard.mn, CC0 1.0) lists none at.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "floor": {
            "type": "integer",
            "nullable": true,
            "example": 12,
            "description": "A company from a building's directory: its floor, from the legal address in the state entity register. null when not said, and for every other place."
          },
          "flat": {
            "type": "string",
            "nullable": true,
            "example": "1204",
            "description": "A company from a building's directory: its flat or office number (N тоот). null when not said."
          },
          "category": {
            "type": "string",
            "nullable": true,
            "example": "pharmacy",
            "description": "A business or landmark: its map category, the one GET /v1/nearby gives. null for any other kind."
          },
          "outline": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "example": {
              "type": "Polygon",
              "coordinates": [
                [
                  [
                    106.9,
                    47.92
                  ],
                  [
                    106.91,
                    47.92
                  ],
                  [
                    106.91,
                    47.93
                  ],
                  [
                    106.9,
                    47.92
                  ]
                ]
              ]
            },
            "description": "A district, khoroo or area: its boundary as a GeoJSON Polygon (a MultiPolygon when it has parts), simplified to about 5 m, 5 decimals (next API patch). A building: its footprint, simplified to about 1 m. null for every other kind, and where the register has no polygon: unknown, never drawn."
          },
          "counts": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "example": {
              "buildings": 101,
              "doors": 0,
              "state_only": 38,
              "source": "core.building, core.door",
              "as_of": "2026-10-26"
            },
            "description": "A district, khoroo or area: current buildings and doors inside its boundary, nothing inside a restricted site. state_only is how many of those buildings are state records with no state address matched; divide by buildings for a share. 0 is a real zero (no door is minted there yet). null for every other kind, and where the register has no polygon: unknown."
          },
          "district_mn": {
            "type": "string",
            "nullable": true,
            "example": "Хан-Уул",
            "description": "A landmark, business or street: the district its point stands in; null for every other kind and when no polygon covers it."
          },
          "footprint_check": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "example": {
              "verdict": "confirmed",
              "source": "osm",
              "confidence": null,
              "checked_at": "2026-11-02"
            },
            "description": "A building: whether its footprint is backed by a second source. verdict is confirmed (two of OSM or Overture, Microsoft and the state record agree), new (one source only, not in OSM) or doubtful (OSM only). source names the footprint it was read from; confidence is null when the run gave none: unknown. It is read the same way outside the nine districts (176,867 buildings, 74,133 confirmed and 102,727 doubtful in run 3), where district is null. null for every other kind and for a building not yet checked."
          },
          "building_type": {
            "type": "string",
            "nullable": true,
            "example": "ger_house",
            "enum": [
              "apartment",
              "ger_house",
              "commercial",
              "public",
              "industrial",
              "garage",
              "other"
            ],
            "description": "A building: what it is, from the register or the map (apartment, ger_house, commercial, public, industrial, garage, other), the same word a search row gives, so a card can say it instead of the generic \"Барилга\". null when the building has no type yet; never guessed. Absent for every other kind."
          },
          "name_is_kind_word": {
            "type": "boolean",
            "nullable": true,
            "example": false,
            "description": "A building: true when its whole name is only a kind word (Үсчин, Дэлгүүр). null when not checked. Absent for every other kind."
          },
          "photo": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "example": {
              "url": "https://upload.wikimedia.org/wikipedia/commons/a/a1/Sukhbaatar_Square.jpg",
              "credit": "https://commons.wikimedia.org/wiki/File:Sukhbaatar_Square.jpg",
              "license": "CC BY-SA 4.0",
              "source": "commons"
            },
            "description": "A landmark or building: one openly licensed photo (Wikimedia Commons) placed within 30 m of its point. Show author (plain text, present when known), then credit (the page that names the author) and license beside it. null when there is none, and for every other kind: show the map from above instead."
          },
          "map_from_above": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "example": {
              "lon": 106.9177,
              "lat": 47.9186,
              "zoom": 19
            },
            "description": "Set only when photo is null: where to point the map from above so the place page keeps its frame (zoom 19 for a building, a door, or a business that sits in a building; 17 for a business with no building, a landmark and anything else, so a store with no building shows its street, not a guessed roof). null when there is a photo."
          }
        },
        "required": [
          "official_address",
          "official_status",
          "unofficial",
          "official_source",
          "official_date",
          "official_line",
          "code",
          "kind",
          "id",
          "name_mn",
          "name_en",
          "long_mn",
          "long_en",
          "point",
          "confidence",
          "source",
          "source_date",
          "parents",
          "lines",
          "floor",
          "flat",
          "category",
          "outline",
          "counts",
          "district_mn",
          "footprint_check",
          "photo",
          "map_from_above"
        ]
      },
      "BuildingEntranceDto": {
        "type": "object",
        "properties": {
          "official_address": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ],
            "description": "The entrance's official address: the door's, else the building's form with the number. null when none."
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ],
            "description": "The level: matched бүртгэлтэй (state register), partial хэсэгчилсэн (public sources), none албан бус."
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched. Clients must show \"unofficial\"."
          },
          "official_source": {
            "type": "string",
            "nullable": true,
            "example": "osm:W1301496712, osm:admin",
            "description": "Where the official address came from, as the register and its record, for example zipcode:4364. null when there is none."
          },
          "official_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-14",
            "description": "The date the official address was recorded, YYYY-MM-DD. null when not known."
          },
          "source_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-14",
            "description": "The date of this entrance's current version. null: unknown."
          },
          "code": {
            "type": "string",
            "nullable": true,
            "example": "7QSVX",
            "description": "The building code. null: no door minted for this entrance yet."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The entrance id. Stable, never shown to people as an address."
          },
          "kind": {
            "type": "string",
            "enum": [
              "door",
              "gate",
              "vehicle_gate",
              "stairwell"
            ],
            "description": "door: a door of a building. gate: a gate for people. vehicle_gate: a gate for vehicles. stairwell: a numbered stairwell entrance of a block."
          },
          "letter": {
            "type": "string",
            "example": "1",
            "nullable": true,
            "description": "Entrance or gate number as people say it. null: not known."
          },
          "floors_served": {
            "nullable": true,
            "example": [
              1,
              9
            ],
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "The floors this entrance serves, as numbers. null when not known."
          },
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "description": "[lon, lat], WGS84, the entrance.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "confidence": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4,
            "nullable": true,
            "description": "Trust level of the point, 0 to 4. 0 with source generated: placed by rule from the footprint (таамаг). Levels: 0 автоматаар байрлуулсан (placed by rule), 1 зурагтай тулгаж шалгасан (checked against imagery), 2 газар дээр нэг удаа баталсан (confirmed once on site), 3 бие даан гурван удаа баталсан (confirmed independently three times), 4 хэмжилтээр баталсан (surveyed)."
          },
          "source": {
            "type": "string",
            "example": "generated",
            "description": "Where the row came from, for example osm, overture, generated, a register or a chain's published list. For a building it names the footprint layer. It does not say the address is official: read official_status for that."
          }
        },
        "required": [
          "official_address",
          "official_status",
          "unofficial",
          "official_source",
          "official_date",
          "source_date",
          "code",
          "id",
          "kind",
          "letter",
          "floors_served",
          "point",
          "confidence",
          "source"
        ]
      },
      "BuildingEntrancesDto": {
        "type": "object",
        "properties": {
          "building": {
            "type": "string",
            "format": "uuid",
            "description": "The building id, as sent."
          },
          "official_address": {
            "nullable": true,
            "description": "The building's official form. null when none.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ]
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ],
            "description": "The level of the building's official address. The level: matched бүртгэлтэй (state register), partial хэсэгчилсэн (public sources), none албан бус (not matched, shown as unofficial)."
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched."
          },
          "official_source": {
            "type": "string",
            "nullable": true,
            "description": "Where the building's official address came from. null when there is none."
          },
          "official_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-14",
            "description": "The date the building's official address was recorded, YYYY-MM-DD. null when not known."
          },
          "entrances": {
            "description": "Numbered entrances first, in number order, then the rest. Empty when none is mapped or generated.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BuildingEntranceDto"
            }
          },
          "entrances_approved": {
            "type": "boolean",
            "description": "false until the building's entrance method is approved; entrances is then empty."
          },
          "note": {
            "type": "string",
            "example": "entrances: not approved for this building",
            "description": "Present when entrances_approved is false."
          }
        },
        "required": [
          "building",
          "official_address",
          "official_status",
          "unofficial",
          "official_source",
          "official_date",
          "entrances",
          "entrances_approved"
        ]
      },
      "DirectoryEntryDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Номин Холдинг",
            "description": "The company's name as the state entity register writes it."
          },
          "floor": {
            "type": "number",
            "nullable": true,
            "example": 12,
            "description": "Floor (давхар). null when the register does not say."
          },
          "unit": {
            "type": "string",
            "nullable": true,
            "example": "1204",
            "description": "Unit (тоот). null when unknown."
          },
          "flat": {
            "type": "string",
            "nullable": true,
            "example": "1204",
            "description": "The flat or office number (N тоот), the same value as unit, named as geocode and nearby name it. null when unknown."
          },
          "category": {
            "type": "string",
            "nullable": true,
            "example": "bank",
            "description": "The map category of the company, for example bank. null when not known."
          },
          "source": {
            "type": "string",
            "example": "ereg",
            "description": "The register the entry comes from."
          },
          "confidence": {
            "type": "number",
            "nullable": true,
            "example": 3,
            "description": "Trust level of the entry, 0 to 4. null means unknown. Levels: 0 автоматаар байрлуулсан (placed by rule), 1 зурагтай тулгаж шалгасан (checked against imagery), 2 газар дээр нэг удаа баталсан (confirmed once on site), 3 бие даан гурван удаа баталсан (confirmed independently three times), 4 хэмжилтээр баталсан (surveyed)."
          },
          "source_date": {
            "type": "string",
            "example": "2026-10-19",
            "description": "Date this version of the entry was recorded."
          }
        },
        "required": [
          "name",
          "floor",
          "unit",
          "flat",
          "category",
          "source",
          "confidence",
          "source_date"
        ]
      },
      "BuildingDirectoryDto": {
        "type": "object",
        "properties": {
          "building": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "The building id, as sent or the one the code names. null for a хашаа code."
          },
          "code": {
            "type": "string",
            "nullable": true,
            "example": "7QSVX",
            "description": "The building's code. null until one is minted."
          },
          "entries": {
            "description": "Registered organizations, by floor (unknown floor last), then unit, then name. Empty when none is known.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DirectoryEntryDto"
            }
          }
        },
        "required": [
          "building",
          "code",
          "entries"
        ]
      },
      "NearEntranceDto": {
        "type": "object",
        "properties": {
          "official_address": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ],
            "description": "The entrance's official address: the door's, else the building's form with the number. null when none."
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ],
            "description": "The level: matched бүртгэлтэй (state register), partial хэсэгчилсэн (public sources), none албан бус."
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched. Clients must show \"unofficial\"."
          },
          "official_source": {
            "type": "string",
            "nullable": true,
            "example": "osm:W1301496712, osm:admin",
            "description": "Where the official address came from, as the register and its record, for example zipcode:4364. null when there is none."
          },
          "official_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-14",
            "description": "The date the official address was recorded, YYYY-MM-DD. null when not known."
          },
          "source_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-14",
            "description": "The date of this entrance's current version. null: unknown."
          },
          "code": {
            "type": "string",
            "nullable": true,
            "example": "7QSVX",
            "description": "The building code. null: no door minted for this entrance yet."
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The entrance id. Stable, never shown to people as an address."
          },
          "kind": {
            "type": "string",
            "enum": [
              "door",
              "gate",
              "vehicle_gate",
              "stairwell"
            ],
            "description": "door: a door of a building. gate: a gate for people. vehicle_gate: a gate for vehicles. stairwell: a numbered stairwell entrance of a block."
          },
          "letter": {
            "type": "string",
            "example": "1",
            "nullable": true,
            "description": "Entrance or gate number as people say it. null: not known."
          },
          "floors_served": {
            "nullable": true,
            "example": [
              1,
              9
            ],
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "The floors this entrance serves, as numbers. null when not known."
          },
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "description": "[lon, lat], WGS84, the entrance.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "confidence": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4,
            "nullable": true,
            "description": "Trust level of the point, 0 to 4. 0 with source generated: placed by rule from the footprint (таамаг). Levels: 0 автоматаар байрлуулсан (placed by rule), 1 зурагтай тулгаж шалгасан (checked against imagery), 2 газар дээр нэг удаа баталсан (confirmed once on site), 3 бие даан гурван удаа баталсан (confirmed independently three times), 4 хэмжилтээр баталсан (surveyed)."
          },
          "source": {
            "type": "string",
            "example": "generated",
            "description": "Where the row came from, for example osm, overture, generated, a register or a chain's published list. For a building it names the footprint layer. It does not say the address is official: read official_status for that."
          },
          "building": {
            "type": "string",
            "format": "uuid",
            "description": "The building the entrance belongs to: GET /v1/address/{id}/entrances lists them all."
          },
          "distance_m": {
            "type": "number",
            "example": 4.2,
            "description": "Metres from the query point."
          }
        },
        "required": [
          "official_address",
          "official_status",
          "unofficial",
          "official_source",
          "official_date",
          "source_date",
          "code",
          "id",
          "kind",
          "letter",
          "floors_served",
          "point",
          "confidence",
          "source",
          "building",
          "distance_m"
        ]
      },
      "NearEntrancesDto": {
        "type": "object",
        "properties": {
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "description": "The query point, as sent.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "results": {
            "description": "Nearest first, within radius. Empty when no entrance is that close.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NearEntranceDto"
            }
          }
        },
        "required": [
          "point",
          "results"
        ]
      },
      "NameBodyDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Сансар бэйкери",
            "minLength": 2,
            "maxLength": 60,
            "description": "The spoken name of your door. At least one letter; no phone number, no e-mail, never a building code."
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "description": "The door it names. Cyrillic lookalike keys and lower case are read."
          }
        },
        "required": [
          "name",
          "code"
        ]
      },
      "NameReceiptDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Сансар бэйкери",
            "description": "As registered, spaces collapsed."
          },
          "code": {
            "type": "string",
            "example": "7QSVX"
          },
          "registered_at": {
            "type": "string",
            "example": "2026-10-04T08:12:40Z"
          },
          "expires_at": {
            "type": "string",
            "example": "2027-10-04T08:12:40Z",
            "description": "After this the name finds nothing and any org may take it."
          },
          "status": {
            "type": "string",
            "enum": [
              "registered",
              "moved",
              "unchanged"
            ],
            "description": "registered: the name is yours from now. moved: your name now names this door. unchanged: it already did."
          }
        },
        "required": [
          "name",
          "code",
          "registered_at",
          "expires_at",
          "status"
        ]
      },
      "OwnNameDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Сансар бэйкери",
            "description": "As registered, spaces collapsed."
          },
          "code": {
            "type": "string",
            "example": "7QSVX"
          },
          "registered_at": {
            "type": "string",
            "example": "2026-10-04T08:12:40Z"
          },
          "expires_at": {
            "type": "string",
            "example": "2027-10-04T08:12:40Z",
            "description": "After this the name finds nothing and any org may take it."
          },
          "expired": {
            "type": "boolean",
            "description": "true after expires_at: it finds nothing, and stays listed until another org takes it."
          },
          "transfer_until": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "When the transfer code you made stops working; null when none is waiting."
          }
        },
        "required": [
          "name",
          "code",
          "registered_at",
          "expires_at",
          "expired",
          "transfer_until"
        ]
      },
      "OwnNamesDto": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "example": 50,
            "description": "Unexpired names one org may hold at once."
          },
          "names": {
            "description": "A to Z.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OwnNameDto"
            }
          }
        },
        "required": [
          "limit",
          "names"
        ]
      },
      "NamedDoorDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Сансар бэйкери"
          },
          "expires_at": {
            "type": "string",
            "example": "2027-10-04T08:12:40Z"
          },
          "door": {
            "description": "As GET /v1/door/{code} answers it: official address first.",
            "allOf": [
              {
                "$ref": "#/components/schemas/DoorDto"
              }
            ]
          }
        },
        "required": [
          "name",
          "expires_at",
          "door"
        ]
      },
      "TransferCodeDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Сансар бэйкери"
          },
          "transfer_code": {
            "type": "string",
            "example": "dnt_7k2m9q4x8r3t6v1w5y0z2b4c",
            "description": "Shown once, never again. Give it to the org that takes the name; anyone holding it can claim the name."
          },
          "transfer_until": {
            "type": "string",
            "example": "2026-10-11T08:12:40Z",
            "description": "Refused after this: 7 days, or the name's expires_at if sooner."
          }
        },
        "required": [
          "name",
          "transfer_code",
          "transfer_until"
        ]
      },
      "TransferCancelDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Сансар бэйкери"
          },
          "cancelled": {
            "type": "boolean",
            "description": "true: a waiting code was cleared. false: none was waiting."
          }
        },
        "required": [
          "name",
          "cancelled"
        ]
      },
      "ClaimBodyDto": {
        "type": "object",
        "properties": {
          "transfer_code": {
            "type": "string",
            "example": "dnt_7k2m9q4x8r3t6v1w5y0z2b4c",
            "description": "The code the holder made with POST .../transfer-code."
          }
        },
        "required": [
          "transfer_code"
        ]
      },
      "ClaimReceiptDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Сансар бэйкери",
            "description": "As registered, spaces collapsed."
          },
          "code": {
            "type": "string",
            "example": "7QSVX"
          },
          "registered_at": {
            "type": "string",
            "example": "2026-10-04T08:12:40Z"
          },
          "expires_at": {
            "type": "string",
            "example": "2027-10-04T08:12:40Z",
            "description": "After this the name finds nothing and any org may take it."
          },
          "status": {
            "type": "string",
            "enum": [
              "transferred"
            ],
            "description": "The name is your org's from now. The door and expires_at are as they were; move it with POST /v1/door-names."
          }
        },
        "required": [
          "name",
          "code",
          "registered_at",
          "expires_at",
          "status"
        ]
      },
      "ChangeDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The id GET /v1/address/{id} takes."
          },
          "kind": {
            "type": "string",
            "enum": [
              "door",
              "business",
              "building",
              "district",
              "khoroo",
              "area",
              "street",
              "landmark"
            ],
            "description": "What the place is. Values, with the word the map shows: door Хаалга, business Байгууллага, building Барилга, district Дүүрэг, khoroo Хороо, area Хороолол, street Гудамж, landmark Газар."
          },
          "state": {
            "type": "string",
            "enum": [
              "current",
              "retired",
              "hidden"
            ],
            "description": "current: fetch it again with GET /v1/address/{id}. retired: drop it, the id is never reused (410 by id). hidden: drop it; a business no longer served (404 by id), it may come back as current. current: the place exists. retired: it is gone and its id is never reused. hidden: it is not shown."
          },
          "changed_at": {
            "type": "string",
            "example": "2026-10-01T14:07:46.934105Z",
            "description": "Last change, UTC, microseconds."
          }
        },
        "required": [
          "id",
          "kind",
          "state",
          "changed_at"
        ]
      },
      "ChangesDto": {
        "type": "object",
        "properties": {
          "since": {
            "type": "string",
            "example": "2026-10-01T00:00:00.000000Z",
            "description": "Start of the window, inclusive."
          },
          "until": {
            "type": "string",
            "example": "2026-10-01T19:00:00.000000Z",
            "description": "End of the window, exclusive: one second before the last index refresh. When next is null, poll again with since=until."
          },
          "changes": {
            "description": "Oldest change first. One row per place, its last change.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChangeDto"
            }
          },
          "next": {
            "type": "string",
            "nullable": true,
            "description": "More in this window: pass as cursor. null: window done."
          }
        },
        "required": [
          "since",
          "until",
          "changes",
          "next"
        ]
      },
      "ConfirmOwnCountsDto": {
        "type": "object",
        "properties": {
          "confirmed": {
            "type": "integer",
            "example": 41,
            "description": "How many confirmations said the door is where the tap was."
          },
          "wrong_location": {
            "type": "integer",
            "example": 3,
            "description": "How many said the door stands elsewhere."
          },
          "missing": {
            "type": "integer",
            "example": 1,
            "description": "How many said the door is not there."
          },
          "duplicate": {
            "type": "integer",
            "example": 0,
            "description": "POST /v1/door/report kind duplicate"
          },
          "unmapped": {
            "type": "integer",
            "example": 2,
            "description": "POST /v1/door/report kind unmapped: a real door with no code yet"
          }
        },
        "required": [
          "confirmed",
          "wrong_location",
          "missing",
          "duplicate",
          "unmapped"
        ]
      },
      "ConfirmOwnDayDto": {
        "type": "object",
        "properties": {
          "confirmed": {
            "type": "integer",
            "example": 41,
            "description": "How many confirmations said the door is where the tap was."
          },
          "wrong_location": {
            "type": "integer",
            "example": 3,
            "description": "How many said the door stands elsewhere."
          },
          "missing": {
            "type": "integer",
            "example": 1,
            "description": "How many said the door is not there."
          },
          "duplicate": {
            "type": "integer",
            "example": 0,
            "description": "POST /v1/door/report kind duplicate"
          },
          "unmapped": {
            "type": "integer",
            "example": 2,
            "description": "POST /v1/door/report kind unmapped: a real door with no code yet"
          },
          "day": {
            "type": "string",
            "example": "2026-10-01",
            "description": "Ulaanbaatar date the driver was on site (observed_at, else received)"
          },
          "drivers": {
            "type": "integer",
            "example": 4,
            "description": "Drivers that day, by your driver ids. Rows sent with no driver id are not counted here."
          }
        },
        "required": [
          "confirmed",
          "wrong_location",
          "missing",
          "duplicate",
          "unmapped",
          "day",
          "drivers"
        ]
      },
      "ConfirmOwnFlaggedDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "7QSVX",
            "nullable": true,
            "description": "null when your drivers named the entrance, not a code"
          },
          "entrance": {
            "type": "string",
            "format": "uuid",
            "description": "The entrance, as in the entrance tile layer"
          },
          "retired": {
            "type": "boolean",
            "description": "true when the door or entrance has since been retired"
          },
          "wrong_location": {
            "type": "integer",
            "example": 2,
            "description": "How many times drivers said the door stands elsewhere."
          },
          "missing": {
            "type": "integer",
            "example": 0,
            "description": "How many times drivers said the door is not there."
          },
          "duplicate": {
            "type": "integer",
            "example": 0,
            "description": "How many times drivers said the door is a duplicate of another."
          },
          "last_at": {
            "type": "string",
            "example": "2026-10-01T06:05:00.000Z",
            "description": "The newest of them, on site"
          }
        },
        "required": [
          "code",
          "entrance",
          "retired",
          "wrong_location",
          "missing",
          "duplicate",
          "last_at"
        ]
      },
      "ConfirmOwnDto": {
        "type": "object",
        "properties": {
          "month": {
            "type": "string",
            "example": "2026-10",
            "description": "The month the numbers are for, YYYY-MM."
          },
          "closed": {
            "type": "boolean",
            "description": "false while confirmations queued offline can still join; true from 8 days after the month ends"
          },
          "totals": {
            "description": "Your confirmations and door reports in the month, by result",
            "allOf": [
              {
                "$ref": "#/components/schemas/ConfirmOwnCountsDto"
              }
            ]
          },
          "drivers": {
            "type": "integer",
            "example": 9,
            "description": "Different drivers in the month, by your driver ids. Never the ids."
          },
          "days": {
            "description": "Days with at least one row, oldest first",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConfirmOwnDayDto"
            }
          },
          "flagged": {
            "description": "Failure points: doors and entrances your drivers said are wrong, missing or a duplicate, most first, at most 100. None inside a restricted site.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConfirmOwnFlaggedDto"
            }
          }
        },
        "required": [
          "month",
          "closed",
          "totals",
          "drivers",
          "days",
          "flagged"
        ]
      },
      "ConfirmBodyDto": {
        "type": "object",
        "properties": {
          "result": {
            "type": "string",
            "enum": [
              "confirmed",
              "wrong_location",
              "missing"
            ],
            "description": "confirmed: the door is where the map shows it (needs tap). wrong_location: the door is real but elsewhere (needs tap at the real door). missing: no door there (no tap). Duplicate and unmapped doors go to POST /v1/door/report."
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "description": "The door or unit, by code. Send code or entrance, not both. A unit code (building or khashaa) takes result confirmed only."
          },
          "entrance": {
            "type": "string",
            "format": "uuid",
            "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b",
            "description": "The entrance, by the id in the entrance tile layer (z15+). For entrances that have no code yet."
          },
          "tap": {
            "example": [
              106.93012,
              47.92011
            ],
            "description": "[lon, lat] WGS84 where the driver tapped the door on the map or imagery. This is the placed point.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "device": {
            "example": [
              106.9302,
              47.9203
            ],
            "description": "[lon, lat] phone GPS on site. A check only, never the placed point: within 40 m of the tap (missing: of the entrance).",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "driver": {
            "type": "string",
            "maxLength": 64,
            "example": "drv-7f3a",
            "description": "Your own opaque id for the driver, so confirmations by different drivers count as independent. Stored only as a hash with your organization. Never a phone number, e-mail or name."
          },
          "note": {
            "type": "string",
            "maxLength": 500,
            "description": "Runs of 6 or more digits and e-mail addresses are removed before storing."
          },
          "observed_at": {
            "type": "string",
            "example": "2026-10-01T14:05:00+08:00",
            "description": "When the driver was on site, if your app queued the confirmation offline. ISO 8601 with a zone, at most 7 days ago."
          }
        },
        "required": [
          "result",
          "device"
        ]
      },
      "ConfirmDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b",
            "description": "Confirmation id. Same id for a repeat."
          },
          "status": {
            "type": "string",
            "enum": [
              "recorded",
              "already_recorded"
            ],
            "description": "already_recorded: the same driver (or your org, with no driver) said the same about this door in the last 24 h."
          },
          "result": {
            "type": "string",
            "enum": [
              "confirmed",
              "wrong_location",
              "missing"
            ],
            "description": "What the driver said. confirmed: the door is where the tap is. wrong_location: it stands elsewhere. missing: it is not there."
          },
          "target": {
            "type": "string",
            "enum": [
              "door",
              "entrance",
              "unit"
            ],
            "description": "unit: the code named a building or khashaa (an arrival)"
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "nullable": true,
            "description": "The door or unit code that was sent. null when an entrance id was sent."
          },
          "entrance": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "The entrance confirmed, also for a building code. null for a unit code: a building or khashaa has no one entrance."
          },
          "moved_m": {
            "type": "number",
            "example": 1.8,
            "nullable": true,
            "description": "Metres from the tap to the entrance on the map. null for missing."
          },
          "gps_m": {
            "type": "number",
            "example": 22.4,
            "description": "Metres from the tap (missing: the entrance) to the phone GPS."
          },
          "observed_at": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-01T06:05:00.000Z",
            "description": "When the driver was on site, UTC. null when not sent."
          },
          "received_at": {
            "type": "string",
            "example": "2026-10-01T06:41:07.123Z",
            "description": "When dock received it, UTC."
          },
          "next": {
            "type": "string",
            "enum": [
              "confidence",
              "review",
              "arrival"
            ],
            "description": "confidence: counts toward the entrance confidence at once (PLAN.md 5). review: a person checks it first. arrival: recorded as an arrival at a building or khashaa; no entrance is raised. No point moves."
          }
        },
        "required": [
          "id",
          "status",
          "result",
          "target",
          "code",
          "entrance",
          "moved_m",
          "gps_m",
          "observed_at",
          "received_at",
          "next"
        ]
      },
      "ConfirmPhotoDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The confirmation the photo belongs to."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "unchanged"
            ],
            "description": "queued: stored with the confirmation. unchanged: this photo already was."
          },
          "sha256": {
            "type": "string",
            "description": "SHA-256 of the photo as stored, after its metadata was removed: not the hash of the file you sent."
          },
          "received_at": {
            "type": "string",
            "example": "2026-10-14T06:12:40.000Z",
            "description": "When dock received the photo, UTC."
          },
          "next": {
            "type": "string",
            "enum": [
              "review"
            ],
            "description": "A person reviews it once the entrance has a door. It is never shown on a public page."
          }
        },
        "required": [
          "id",
          "status",
          "sha256",
          "received_at",
          "next"
        ]
      },
      "BusinessClaimBodyDto": {
        "type": "object",
        "properties": {
          "reg_number": {
            "type": "string",
            "example": "5012345",
            "description": "The 7-digit number in the state legal-entity register (the company, not a person)."
          },
          "name": {
            "type": "string",
            "maxLength": 200,
            "example": "Сансар бэйкери ХХК",
            "description": "The name as registered."
          },
          "phone": {
            "example": [
              "99106200"
            ],
            "description": "Mongolian numbers, 8 digits each; stored as +976 numbers in the phone field. Never put a number in name, hours or sells.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "hours": {
            "type": "string",
            "maxLength": 200,
            "example": "Да-Ня 09:00-21:00"
          },
          "sells": {
            "type": "string",
            "maxLength": 300,
            "example": "талх, боов, кофе"
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "description": "The unit it stands in, by code. Send code or point, not both."
          },
          "point": {
            "example": [
              106.9303,
              47.9202
            ],
            "description": "[lon, lat] of the business. Send code or point, not both.",
            "type": "array",
            "items": {
              "type": "number"
            }
          }
        },
        "required": [
          "reg_number",
          "name"
        ]
      },
      "BusinessClaimDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "already_queued"
            ],
            "description": "already_queued: the same register number and name came from this key in the last 24 h."
          },
          "received_at": {
            "type": "string",
            "example": "2026-10-25T06:41:07.123Z"
          },
          "state": {
            "type": "string",
            "enum": [
              "pending"
            ],
            "description": "Pending until the register number is matched to the state register. Only a matched business is published, on its unit, with its code."
          }
        },
        "required": [
          "id",
          "status",
          "received_at",
          "state"
        ]
      },
      "BusinessClaimStatusDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b"
          },
          "received_at": {
            "type": "string",
            "example": "2026-10-25T06:41:07.123Z"
          },
          "state": {
            "type": "string",
            "enum": [
              "pending",
              "verified",
              "refused"
            ],
            "description": "verified: matched to the state register and published on its unit. pending: waiting, see reason."
          },
          "reason": {
            "type": "string",
            "nullable": true,
            "example": "not_in_register",
            "description": "Why it is not verified yet; null once verified."
          },
          "decided_at": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "When the state was decided; null while pending."
          }
        },
        "required": [
          "id",
          "received_at",
          "state",
          "reason",
          "decided_at"
        ]
      },
      "PublicCardPhotoDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "example": "/v1/business/photos/0190a3c2-7b1e-7c3a-9d4e-5f6a7b8c9d0e"
          },
          "kind": {
            "type": "string",
            "nullable": true,
            "enum": [
              "outside",
              "inside",
              "product",
              "menu",
              "team"
            ]
          }
        },
        "required": [
          "id",
          "url",
          "kind"
        ]
      },
      "PublicCardButtonDto": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "call",
              "order",
              "book",
              "buy",
              "website",
              "facebook"
            ]
          },
          "url": {
            "type": "string",
            "example": "https://example.mn/book"
          }
        },
        "required": [
          "kind"
        ]
      },
      "PublicCardMenuDto": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "item",
              "service"
            ]
          },
          "section": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string"
          },
          "price": {
            "type": "number",
            "nullable": true,
            "description": "In tugrik; null means ask."
          }
        },
        "required": [
          "kind",
          "section",
          "name",
          "price"
        ]
      },
      "PublicCardPostDto": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string"
          },
          "ends_on": {
            "type": "string",
            "example": "2026-11-30",
            "description": "Shown until the end of this day in Ulaanbaatar."
          }
        },
        "required": [
          "text",
          "ends_on"
        ]
      },
      "PublicCardDto": {
        "type": "object",
        "properties": {
          "photos": {
            "description": "Empty below 3 photos.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicCardPhotoDto"
            }
          },
          "buttons": {
            "description": "Owner order; the first is the main button, the second the one the owner chose.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicCardButtonDto"
            }
          },
          "phone": {
            "description": "Business phone numbers, 8 digits.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "highlight": {
            "type": "string",
            "nullable": true
          },
          "accent": {
            "type": "string",
            "enum": [
              "teal",
              "orange",
              "blue",
              "red",
              "green",
              "plum"
            ]
          },
          "attributes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "menu": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicCardMenuDto"
            }
          },
          "posts": {
            "description": "Posts that have not ended.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicCardPostDto"
            }
          },
          "edited_at": {
            "type": "string",
            "example": "2026-11-02T06:41:07.123Z"
          }
        },
        "required": [
          "photos",
          "buttons",
          "phone",
          "description",
          "highlight",
          "accent",
          "attributes",
          "menu",
          "posts",
          "edited_at"
        ]
      },
      "TilequeryPointDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Point"
            ],
            "description": "GeoJSON type, Point."
          },
          "coordinates": {
            "example": [
              106.9177012,
              47.9186023
            ],
            "description": "The point of the feature nearest the point sent, WGS84 [lon, lat]; the point sent when it is inside. The 7th decimal is a mark for your organization (PLAN.md 19).",
            "type": "array",
            "items": {
              "type": "number"
            }
          }
        },
        "required": [
          "type",
          "coordinates"
        ]
      },
      "TilequeryInfoDto": {
        "type": "object",
        "properties": {
          "distance": {
            "type": "number",
            "example": 12.4,
            "description": "Metres from the point sent to the nearest part of the feature, to 0.1 m. 0: the point is inside it."
          },
          "geometry": {
            "type": "string",
            "enum": [
              "polygon",
              "linestring",
              "point"
            ],
            "description": "The feature's geometry type, as Mapbox's."
          },
          "layer": {
            "type": "string",
            "enum": [
              "building",
              "entrance",
              "place"
            ],
            "description": "The tile source and layer the feature is in."
          }
        },
        "required": [
          "distance",
          "geometry",
          "layer"
        ]
      },
      "TilequeryPropertiesDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The building, entrance or place id, as in its tile. Never an address."
          },
          "name_mn": {
            "type": "string",
            "nullable": true,
            "description": "Building or place only."
          },
          "name_en": {
            "type": "string",
            "nullable": true,
            "description": "Building or place only."
          },
          "type": {
            "type": "string",
            "nullable": true,
            "enum": [
              "apartment",
              "ger_house",
              "commercial",
              "public",
              "industrial",
              "garage",
              "other"
            ],
            "description": "Building only."
          },
          "status": {
            "type": "string",
            "enum": [
              "planned",
              "under_construction",
              "built"
            ],
            "description": "Building only."
          },
          "height_m": {
            "type": "number",
            "nullable": true,
            "description": "Building only. Metres."
          },
          "levels": {
            "type": "integer",
            "nullable": true,
            "description": "Building only."
          },
          "height_source": {
            "type": "string",
            "nullable": true,
            "example": "estimated:area",
            "description": "Building only: where height_m came from. osm:height a tag; levels levels x 3.1 m; default:* a type default; estimated:* footprint shape and size; unknown none."
          },
          "height_confidence": {
            "type": "integer",
            "nullable": true,
            "example": 0,
            "description": "Building only: 3 a tag or editor, 2 levels, 1 type default, 0 estimated. 0 and 1 are estimates, never measurements. null: no height."
          },
          "building_number": {
            "type": "string",
            "nullable": true,
            "example": "52а",
            "description": "Building only: official building number from the state register. null: no matched or partial official form."
          },
          "building_name": {
            "type": "string",
            "nullable": true,
            "example": "Сансар төв",
            "description": "Building only: the building's name when it is a name, not a purpose. null: no name or no official form."
          },
          "footprint_check": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "example": {
              "verdict": "confirmed",
              "source": "osm",
              "confidence": null,
              "checked_at": "2026-11-02"
            },
            "description": "Building only: whether its footprint is backed by a second source. verdict is confirmed, new or doubtful; source and confidence as on GET /v1/address/{id}. null: not checked yet. Not a tile field: the vector tile does not carry it."
          },
          "cat": {
            "type": "string",
            "nullable": true,
            "example": "pharmacy",
            "description": "Place only: the map category (bank, pharmacy, stop, religion, etc.)."
          },
          "rank": {
            "type": "number",
            "nullable": true,
            "example": 37,
            "description": "Place only: the map rank (higher shows over lower in collisions)."
          },
          "kind": {
            "type": "string",
            "enum": [
              "door",
              "gate",
              "vehicle_gate",
              "stairwell"
            ],
            "description": "Entrance only. door: a door of a building. gate: a gate for people. vehicle_gate: a gate for vehicles. stairwell: a numbered stairwell entrance of a block."
          },
          "letter": {
            "type": "string",
            "nullable": true,
            "example": "A",
            "description": "Entrance only."
          },
          "building_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Entrance only: its building. null: none on record."
          },
          "confidence": {
            "type": "integer",
            "nullable": true,
            "example": 2,
            "description": "Trust level, 0 to 4. null: not rated yet. Levels: 0 автоматаар байрлуулсан (placed by rule), 1 зурагтай тулгаж шалгасан (checked against imagery), 2 газар дээр нэг удаа баталсан (confirmed once on site), 3 бие даан гурван удаа баталсан (confirmed independently three times), 4 хэмжилтээр баталсан (surveyed)."
          },
          "source": {
            "type": "string",
            "example": "osm",
            "description": "Where the row came from, for example osm or generated."
          },
          "tilequery": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TilequeryInfoDto"
              }
            ],
            "description": "Which layer the feature is in and how far it is from the point sent."
          }
        },
        "required": [
          "id",
          "confidence",
          "source",
          "tilequery"
        ]
      },
      "TilequeryFeatureDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ],
            "description": "GeoJSON type, Feature."
          },
          "geometry": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TilequeryPointDto"
              }
            ],
            "description": "The point of the feature nearest the point sent."
          },
          "properties": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TilequeryPropertiesDto"
              }
            ],
            "description": "The feature's own values. Which ones are set depends on the layer."
          }
        },
        "required": [
          "type",
          "geometry",
          "properties"
        ]
      },
      "TilequeryDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ],
            "description": "The answer is GeoJSON: a map source takes it as it is."
          },
          "features": {
            "description": "Nearest first, then by layer and id. Up to limit.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TilequeryFeatureDto"
            }
          }
        },
        "required": [
          "type",
          "features"
        ]
      },
      "RouteMeasuredDto": {
        "type": "object",
        "properties": {
          "month": {
            "type": "string",
            "example": "2026-08",
            "description": "The month of speeds read: the latest GET /v1/traces/roads publishes."
          },
          "band": {
            "type": "string",
            "enum": [
              "am_peak",
              "pm_peak",
              "off_peak"
            ],
            "nullable": true,
            "example": "am_peak",
            "description": "The hour band of depart_at whose speeds were read (GET /v1/traces/roads?band=). null: no depart_at, all hours."
          },
          "roads_m": {
            "type": "number",
            "example": 1240,
            "description": "Metres of the line on roads with a published moving speed that month. 0: none, and duration_s is the free-flow duration_s."
          },
          "duration_s": {
            "type": "number",
            "example": 401,
            "description": "Seconds along the routed line with those roads driven at their measured moving speed, the rest at the router's speeds. Moving speed leaves out stops under 3 km/h, so a queue at a light is not in it. A month average over the band's hours, or all hours."
          }
        },
        "required": [
          "month",
          "band",
          "roads_m",
          "duration_s"
        ]
      },
      "LineStringDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "LineString"
            ],
            "description": "GeoJSON type, LineString."
          },
          "coordinates": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              }
            },
            "example": [
              [
                106.91,
                47.91
              ],
              [
                106.9299,
                47.9198
              ]
            ],
            "description": "The points of the line, [lon, lat], in order."
          }
        },
        "required": [
          "type",
          "coordinates"
        ]
      },
      "RouteStepDto": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "depart",
              "left",
              "right",
              "slight_left",
              "slight_right",
              "sharp_left",
              "sharp_right",
              "uturn",
              "straight",
              "keep_left",
              "keep_right",
              "ramp_left",
              "ramp_right",
              "merge",
              "roundabout",
              "arrive",
              "arrive_left",
              "arrive_right"
            ],
            "description": "What to do at location. arrive_left and arrive_right: the entrance is on that side of the road."
          },
          "location": {
            "example": [
              106.9177,
              47.9186
            ],
            "description": "Where on the line it is done, lon,lat.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "distance_m": {
            "type": "number",
            "example": 240,
            "description": "Metres along the road from here to the next step."
          },
          "duration_s": {
            "type": "number",
            "example": 41,
            "description": "Seconds from here to the next step at free-flow speeds."
          },
          "street": {
            "type": "string",
            "nullable": true,
            "example": "Энхтайваны өргөн чөлөө",
            "description": "The road taken here, as OpenStreetMap names it; null when unnamed."
          },
          "voice": {
            "example": [
              "right"
            ],
            "description": "Ids of the Mongolian voice phrases, in the order spoken (the driver app's phrase set, PWA /voice/mn/phrases.json). The app says a distance phrase (in_50 to in_1000) before them. The last driving step adds walk when the entrance is over 15 m from the road.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "signal": {
            "type": "boolean",
            "example": false,
            "description": "true when the maneuver is within 20 m of a mapped traffic signal (OpenStreetMap highway=traffic_signals); driving routes only, false otherwise. Position only: no live signal state. A turn at a signal says so in mn and en (\"Гэрлэн дохионы уулзварт ...\")."
          },
          "mn": {
            "type": "string",
            "example": "Баруун тийш эргэнэ үү: Энхтайваны өргөн чөлөө.",
            "description": "The step in Mongolian, ready to show or speak."
          },
          "en": {
            "type": "string",
            "example": "Turn right onto Энхтайваны өргөн чөлөө.",
            "description": "The step in English."
          }
        },
        "required": [
          "kind",
          "location",
          "distance_m",
          "duration_s",
          "street",
          "voice",
          "signal",
          "mn",
          "en"
        ]
      },
      "RouteLegDto": {
        "type": "object",
        "properties": {
          "distance_m": {
            "type": "number",
            "example": 1676,
            "description": "Metres from one stop to the next along the road network."
          },
          "duration_s": {
            "type": "number",
            "example": 295,
            "description": "Seconds from one stop to the next at the router's free-flow speeds."
          },
          "floor": {
            "type": "integer",
            "example": 0,
            "description": "The floor this leg is on: 0 for every road leg. Indoor legs, when a venue has walkways, carry their own floor (negative below ground). Not the PLAN 5 level of a point."
          },
          "steps": {
            "description": "Turn-by-turn, in order: depart first, an arrive step last (at the end of the road; the walk to the entrance is to.gap_m and is said in the last step when over 15 m).",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RouteStepDto"
            }
          }
        },
        "required": [
          "distance_m",
          "duration_s",
          "floor",
          "steps"
        ]
      },
      "RouteDoorDto": {
        "type": "object",
        "properties": {
          "official_address": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ],
            "description": "The official address of the door."
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ],
            "description": "The level of the door's official address. The level: matched бүртгэлтэй (state register), partial хэсэгчилсэн (public sources), none албан бус (not matched, shown as unofficial)."
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched. Clients must show \"unofficial\"."
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "description": "The building code, five characters."
          },
          "natural_mn": {
            "type": "string",
            "example": "Сансар А 8",
            "nullable": true,
            "description": "The Mongolian spoken form of the address. null when not known yet."
          },
          "natural_en": {
            "type": "string",
            "example": "Sansar A 8",
            "nullable": true,
            "description": "The English spoken form of the address. null when not known yet."
          },
          "entrance": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EntranceDto"
              }
            ],
            "description": "The entrance the door belongs to."
          },
          "confidence": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4,
            "nullable": true,
            "description": "Trust level, 0 to 4. null means unknown. Levels: 0 автоматаар байрлуулсан (placed by rule), 1 зурагтай тулгаж шалгасан (checked against imagery), 2 газар дээр нэг удаа баталсан (confirmed once on site), 3 бие даан гурван удаа баталсан (confirmed independently three times), 4 хэмжилтээр баталсан (surveyed)."
          }
        },
        "required": [
          "official_address",
          "official_status",
          "unofficial",
          "code",
          "natural_mn",
          "natural_en",
          "entrance",
          "confidence"
        ]
      },
      "RouteEntranceDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The entrance id, as sent."
          },
          "building": {
            "type": "string",
            "format": "uuid",
            "description": "Its building."
          },
          "code": {
            "type": "string",
            "nullable": true,
            "example": "7QSVX",
            "description": "The building code. null: no door minted for this entrance yet."
          },
          "official_address": {
            "nullable": true,
            "description": "The door's, else the building's form with the number.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ]
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ],
            "description": "The level of the entrance's official address. The level: matched бүртгэлтэй (state register), partial хэсэгчилсэн (public sources), none албан бус (not matched, shown as unofficial)."
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched. Clients must show \"unofficial\"."
          },
          "kind": {
            "type": "string",
            "enum": [
              "door",
              "gate",
              "vehicle_gate",
              "stairwell"
            ],
            "description": "door: a door of a building. gate: a gate for people. vehicle_gate: a gate for vehicles. stairwell: a numbered stairwell entrance of a block."
          },
          "letter": {
            "type": "string",
            "example": "1",
            "nullable": true,
            "description": "Entrance or gate number as people say it. null: not known."
          },
          "confidence": {
            "type": "integer",
            "minimum": 0,
            "maximum": 4,
            "nullable": true,
            "description": "Trust level of the point, 0 to 4. 0 with source generated: placed by rule from the footprint (таамаг). Levels: 0 автоматаар байрлуулсан (placed by rule), 1 зурагтай тулгаж шалгасан (checked against imagery), 2 газар дээр нэг удаа баталсан (confirmed once on site), 3 бие даан гурван удаа баталсан (confirmed independently three times), 4 хэмжилтээр баталсан (surveyed)."
          },
          "source": {
            "type": "string",
            "example": "generated",
            "description": "Where the entrance point came from, for example generated, osm or a confirmation."
          }
        },
        "required": [
          "id",
          "building",
          "code",
          "official_address",
          "official_status",
          "unofficial",
          "kind",
          "letter",
          "confidence",
          "source"
        ]
      },
      "RouteUnitDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "7QSVX",
            "description": "The unit code, five characters."
          },
          "kind": {
            "type": "string",
            "enum": [
              "building",
              "khashaa"
            ],
            "description": "building Барилга: a building with a code. khashaa Хашаа: a ger plot with a code."
          },
          "official_address": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ],
            "description": "The official address of the building or ger plot."
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ],
            "description": "The level of the unit's official address. The level: matched бүртгэлтэй (state register), partial хэсэгчилсэн (public sources), none албан бус (not matched, shown as unofficial)."
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched. Clients must show \"unofficial\"."
          },
          "street_side": {
            "type": "boolean",
            "description": "true: the end is the gate, or the outline of the building or khashaa at the street, within about 25 m of where the line meets the street. false: the outline is farther than that from the street, the walk is longer."
          }
        },
        "required": [
          "code",
          "kind",
          "official_address",
          "official_status",
          "unofficial",
          "street_side"
        ]
      },
      "RouteEndDto": {
        "type": "object",
        "properties": {
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "description": "[lon, lat] asked for: the entrance when a code or an entrance id was given",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "snapped": {
            "example": [
              106.9299,
              47.9198
            ],
            "description": "[lon, lat] where the routed line starts or ends, on the road network",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "gap_m": {
            "type": "number",
            "example": 34.2,
            "description": "Straight-line metres between point and snapped. Not routed: the last steps to the door are on foot, through a yard or a gate the road network does not have."
          },
          "door": {
            "nullable": true,
            "description": "The door, when this end was given as a code.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteDoorDto"
              }
            ]
          },
          "entrance": {
            "nullable": true,
            "description": "The entrance, when this end was given as an entrance id. Generated ones (confidence 0) show as таамаг.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteEntranceDto"
              }
            ]
          },
          "source_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-19",
            "description": "The date of the door, unit or entrance this end was given as: its current version, or the register's own date for a door. null for a bare point and when not known."
          },
          "unit": {
            "description": "Present only when this end was given as a unit code. The address unit (building or khashaa). The route ends at its street side.",
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteUnitDto"
              }
            ]
          }
        },
        "required": [
          "point",
          "snapped",
          "gap_m",
          "door",
          "entrance",
          "source_date"
        ]
      },
      "RouteClosuresDto": {
        "type": "object",
        "properties": {
          "as_of": {
            "type": "string",
            "example": "2026-10-02",
            "description": "The route day: today, Ulaanbaatar calendar."
          },
          "avoided": {
            "example": [
              "cl-000001"
            ],
            "description": "Closures active on as_of (GET /v1/closures), in id order. Each ring was sent to the router as an area no road may cross, whether or not the route came near it. Empty: none that day.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "as_of",
          "avoided"
        ]
      },
      "RouteDto": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "driving",
              "walking",
              "cycling"
            ],
            "description": "How the trip is made: driving, walking or cycling."
          },
          "distance_m": {
            "type": "number",
            "example": 2140,
            "description": "Metres along the routed line, from.snapped to to.snapped"
          },
          "duration_s": {
            "type": "number",
            "example": 312,
            "description": "Seconds along the routed line at the router's free-flow speeds. No live traffic."
          },
          "measured": {
            "nullable": true,
            "description": "Driving only: the time with all partners' measured speeds per road (GET /v1/traces/roads). null when walking or cycling, or when the speeds could not be read for this answer; the route is never refused for it.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteMeasuredDto"
              }
            ]
          },
          "expected_duration_s": {
            "type": "integer",
            "example": 2100,
            "nullable": true,
            "description": "Driving only: seconds with a typical load on each road, by road class, hour and weekday (depart_at, else now, Ulaanbaatar time). traffic_source says where the load comes from. null when walking or cycling, or when the edges could not be read; duration_s is then the only time."
          },
          "traffic_source": {
            "type": "string",
            "enum": [
              "model",
              "probes"
            ],
            "example": "model",
            "description": "Where expected_duration_s gets its load: model, a table of road class x hour x weekday; probes, speeds measured from partners' phones (not yet)."
          },
          "traffic_note": {
            "type": "string",
            "example": "замын ачааллыг тооцсон, ойролцоогоор",
            "description": "The label to show beside expected_duration_s."
          },
          "geometry": {
            "description": "GeoJSON, WGS84. Ends at to.snapped; the gap to the entrance is not drawn.",
            "allOf": [
              {
                "$ref": "#/components/schemas/LineStringDto"
              }
            ]
          },
          "legs": {
            "description": "One per hop, in order: from to via[0], via[0] to via[1], and so on, the last to to. One without via. Each rounded on its own, so they may add up to a metre or a second off distance_m and duration_s.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RouteLegDto"
            }
          },
          "from": {
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteEndDto"
              }
            ],
            "description": "Where the route starts, as a route end."
          },
          "via": {
            "description": "The via ends in the order sent, each as a route end: snapped is where the line passes it, gap_m the walk from there. Empty without via.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RouteEndDto"
            }
          },
          "to": {
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteEndDto"
              }
            ],
            "description": "Where the route ends, as a route end."
          },
          "closures": {
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteClosuresDto"
              }
            ],
            "description": "The closures the router avoided for this answer (GET /v1/closures)."
          },
          "source": {
            "type": "string",
            "example": "valhalla; © OpenStreetMap contributors",
            "description": "Where the route comes from: the router and the map data, with the credit to show."
          }
        },
        "required": [
          "mode",
          "distance_m",
          "duration_s",
          "measured",
          "expected_duration_s",
          "traffic_source",
          "traffic_note",
          "geometry",
          "legs",
          "from",
          "via",
          "to",
          "closures",
          "source"
        ]
      },
      "MatrixDto": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "driving",
              "walking",
              "cycling"
            ],
            "description": "How the trip is made: driving, walking or cycling."
          },
          "durations_s": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number",
                "nullable": true
              }
            },
            "example": [
              [
                312,
                null
              ],
              [
                0,
                845
              ]
            ],
            "description": "durations_s[i][j]: seconds from from[i] to to[j] along the road network at the router's free-flow speeds, as duration_s in GET /v1/route. No live traffic, no measured speeds. null: no path between them, closures avoided."
          },
          "distances_m": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number",
                "nullable": true
              }
            },
            "example": [
              [
                2140,
                null
              ],
              [
                0,
                6020
              ]
            ],
            "description": "distances_m[i][j]: metres from from[i].snapped to to[j].snapped. null where durations_s is null."
          },
          "from": {
            "description": "The sources in the order asked, each as a route end.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RouteEndDto"
            }
          },
          "to": {
            "description": "The targets in the order asked, each as a route end.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RouteEndDto"
            }
          },
          "closures": {
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteClosuresDto"
              }
            ],
            "description": "The closures the router avoided for this answer (GET /v1/closures)."
          },
          "source": {
            "type": "string",
            "example": "valhalla; © OpenStreetMap contributors",
            "description": "Where the matrix comes from: the router and the map data, with the credit to show."
          }
        },
        "required": [
          "mode",
          "durations_s",
          "distances_m",
          "from",
          "to",
          "closures",
          "source"
        ]
      },
      "IsochronePropertiesDto": {
        "type": "object",
        "properties": {
          "contour": {
            "type": "integer",
            "example": 10,
            "description": "Minutes: the area reached from from within this time."
          },
          "metric": {
            "type": "string",
            "enum": [
              "time"
            ],
            "description": "What contour counts. Always time: minutes, as Mapbox's contours_minutes."
          }
        },
        "required": [
          "contour",
          "metric"
        ]
      },
      "IsochroneGeometryDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Polygon",
              "MultiPolygon"
            ],
            "description": "Polygon, or MultiPolygon when the area is in parts."
          },
          "coordinates": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "array",
                "items": {}
              }
            },
            "example": [
              [
                [
                  106.9137,
                  47.9483
                ],
                [
                  106.9127,
                  47.9446
                ],
                [
                  106.9201,
                  47.9409
                ],
                [
                  106.9137,
                  47.9483
                ]
              ]
            ],
            "description": "GeoJSON, WGS84 [lon, lat]: rings for a Polygon, polygons of rings for a MultiPolygon. Every ring closed."
          }
        },
        "required": [
          "type",
          "coordinates"
        ]
      },
      "IsochroneFeatureDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ],
            "description": "GeoJSON type, Feature."
          },
          "properties": {
            "allOf": [
              {
                "$ref": "#/components/schemas/IsochronePropertiesDto"
              }
            ],
            "description": "The contour this area stands for."
          },
          "geometry": {
            "allOf": [
              {
                "$ref": "#/components/schemas/IsochroneGeometryDto"
              }
            ],
            "description": "The area, a Polygon or MultiPolygon in WGS84."
          }
        },
        "required": [
          "type",
          "properties",
          "geometry"
        ]
      },
      "IsochroneDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ],
            "description": "The answer is GeoJSON: a map source takes it as it is."
          },
          "features": {
            "description": "One feature per contour, the largest first, so drawn in order each smaller one lies on top. Each area is what the router reaches at free-flow speeds, closures avoided; a smaller contour lies inside a larger one.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IsochroneFeatureDto"
            }
          },
          "mode": {
            "type": "string",
            "enum": [
              "driving",
              "walking",
              "cycling"
            ],
            "description": "How the trip is made: driving, walking or cycling."
          },
          "from": {
            "description": "Where the areas are reached from, as a route end.",
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteEndDto"
              }
            ]
          },
          "closures": {
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteClosuresDto"
              }
            ],
            "description": "The closures the router avoided for this answer (GET /v1/closures)."
          },
          "source": {
            "type": "string",
            "example": "valhalla; © OpenStreetMap contributors",
            "description": "Where the areas come from: the router and the map data, with the credit to show."
          }
        },
        "required": [
          "type",
          "features",
          "mode",
          "from",
          "closures",
          "source"
        ]
      },
      "TracepointDto": {
        "type": "object",
        "properties": {
          "matchings_index": {
            "type": "integer",
            "example": 0,
            "description": "The matching this point lies on, an index into matchings."
          },
          "location": {
            "example": [
              106.9203,
              47.9189
            ],
            "description": "[lon, lat] of the point on the matched line.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "gap_m": {
            "type": "number",
            "example": 6.4,
            "description": "Straight-line metres from the point sent to location."
          }
        },
        "required": [
          "matchings_index",
          "location",
          "gap_m"
        ]
      },
      "MatchingDto": {
        "type": "object",
        "properties": {
          "distance_m": {
            "type": "number",
            "example": 2140,
            "description": "Metres along the matched line."
          },
          "duration_s": {
            "type": "number",
            "example": 298,
            "description": "Seconds along the matched line at the router's free-flow speed on each road, without the turn costs GET /v1/route adds. Not the time the trace took: that is in its timestamps."
          },
          "geometry": {
            "description": "GeoJSON, WGS84: the roads the trace went along, in its order.",
            "allOf": [
              {
                "$ref": "#/components/schemas/LineStringDto"
              }
            ]
          }
        },
        "required": [
          "distance_m",
          "duration_s",
          "geometry"
        ]
      },
      "MatchDto": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "driving",
              "walking",
              "cycling"
            ],
            "description": "How the trip is made: driving, walking or cycling."
          },
          "matchings": {
            "description": "The trace on the road network, in its order. More than one where it breaks: two points too far apart for any road between them in the time given, as a phone that lost its signal.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MatchingDto"
            }
          },
          "tracepoints": {
            "type": "array",
            "items": {
              "nullable": true,
              "allOf": [
                {
                  "$ref": "#/components/schemas/TracepointDto"
                }
              ]
            },
            "description": "One per point sent, in its order. null: no road for this point, or it is inside a restricted site; either way left out of the match."
          },
          "source": {
            "type": "string",
            "example": "valhalla; © OpenStreetMap contributors",
            "description": "Where the matching comes from: the router and the map data, with the credit to show."
          }
        },
        "required": [
          "mode",
          "matchings",
          "tracepoints",
          "source"
        ]
      },
      "TripLegDto": {
        "type": "object",
        "properties": {
          "distance_m": {
            "type": "number",
            "example": 1676,
            "description": "Metres from one stop to the next along the road network."
          },
          "duration_s": {
            "type": "number",
            "example": 295,
            "description": "Seconds from one stop to the next at the router's free-flow speeds."
          }
        },
        "required": [
          "distance_m",
          "duration_s"
        ]
      },
      "TripDto": {
        "type": "object",
        "properties": {
          "distance_m": {
            "type": "number",
            "example": 7119,
            "description": "Metres along the whole trip."
          },
          "duration_s": {
            "type": "number",
            "example": 1162,
            "description": "Seconds on the road along the whole trip at the router's free-flow speeds. No live traffic, no measured speeds, no time at the stops."
          },
          "geometry": {
            "description": "GeoJSON, WGS84: the trip in the order driven, snapped stop to snapped stop.",
            "allOf": [
              {
                "$ref": "#/components/schemas/LineStringDto"
              }
            ]
          },
          "legs": {
            "description": "One per hop in the order driven: legs[k] goes from the stop with waypoint_index k to the one with k + 1; on a round trip the last goes back to the first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TripLegDto"
            }
          }
        },
        "required": [
          "distance_m",
          "duration_s",
          "geometry",
          "legs"
        ]
      },
      "TripWaypointDto": {
        "type": "object",
        "properties": {
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "description": "[lon, lat] asked for: the entrance when a code or an entrance id was given",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "snapped": {
            "example": [
              106.9299,
              47.9198
            ],
            "description": "[lon, lat] where the routed line starts or ends, on the road network",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "gap_m": {
            "type": "number",
            "example": 34.2,
            "description": "Straight-line metres between point and snapped. Not routed: the last steps to the door are on foot, through a yard or a gate the road network does not have."
          },
          "door": {
            "nullable": true,
            "description": "The door, when this end was given as a code.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteDoorDto"
              }
            ]
          },
          "entrance": {
            "nullable": true,
            "description": "The entrance, when this end was given as an entrance id. Generated ones (confidence 0) show as таамаг.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteEntranceDto"
              }
            ]
          },
          "source_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-19",
            "description": "The date of the door, unit or entrance this end was given as: its current version, or the register's own date for a door. null for a bare point and when not known."
          },
          "unit": {
            "description": "Present only when this end was given as a unit code. The address unit (building or khashaa). The route ends at its street side.",
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteUnitDto"
              }
            ]
          },
          "waypoint_index": {
            "type": "integer",
            "example": 2,
            "description": "Where this stop comes in the trip: 0 is the first, always the first sent."
          }
        },
        "required": [
          "point",
          "snapped",
          "gap_m",
          "door",
          "entrance",
          "source_date",
          "waypoint_index"
        ]
      },
      "OptimizedTripDto": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "driving",
              "walking",
              "cycling"
            ],
            "description": "How the trip is made: driving, walking or cycling."
          },
          "roundtrip": {
            "type": "boolean",
            "description": "true: the trip goes back to the first stop. false: it ends at the last stop sent."
          },
          "trips": {
            "description": "One trip, as Mapbox's answer holds it: a list.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TripDto"
            }
          },
          "waypoints": {
            "description": "One per stop, in the order sent, each as a route end with its place in the trip.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TripWaypointDto"
            }
          },
          "closures": {
            "allOf": [
              {
                "$ref": "#/components/schemas/RouteClosuresDto"
              }
            ],
            "description": "The closures the router avoided for this answer (GET /v1/closures)."
          },
          "source": {
            "type": "string",
            "example": "valhalla; © OpenStreetMap contributors",
            "description": "Where the trip comes from: the router and the map data, with the credit to show."
          }
        },
        "required": [
          "mode",
          "roundtrip",
          "trips",
          "waypoints",
          "closures",
          "source"
        ]
      },
      "ClosureItemDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cl-000001",
            "description": "The closure id, as GET /v1/closures/{id} takes it. Never reused."
          },
          "kind": {
            "type": "string",
            "enum": [
              "flood",
              "washout",
              "bridge_out",
              "snow",
              "mud",
              "works",
              "other"
            ],
            "description": "What closed the road. flood, washout, bridge_out (bridge gone), snow, mud, works (road works) or other."
          },
          "from": {
            "type": "string",
            "example": "2026-10-02",
            "description": "The first day the closure counts, YYYY-MM-DD, Ulaanbaatar calendar."
          },
          "to": {
            "type": "string",
            "example": null,
            "nullable": true,
            "description": "The last day the closure counts, YYYY-MM-DD. null while it has no end."
          },
          "confidence": {
            "type": "number",
            "example": 0.5,
            "description": "One partner's word, not field checked."
          },
          "perimeter_m": {
            "type": "number",
            "example": 120,
            "description": "The length of the ring around the closure, in metres."
          },
          "vertices": {
            "type": "integer",
            "example": 5,
            "description": "Ring vertices, the closing one included."
          },
          "ring": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              }
            },
            "example": [
              [
                102.1003,
                46.79981
              ],
              [
                102.1003,
                46.80008
              ],
              [
                102.10006,
                46.80008
              ],
              [
                102.10006,
                46.79981
              ],
              [
                102.1003,
                46.79981
              ]
            ],
            "description": "Closed ring in [lon, lat], 7 decimals. Send it as one of Valhalla's exclude_polygons."
          }
        },
        "required": [
          "id",
          "kind",
          "from",
          "to",
          "confidence",
          "perimeter_m",
          "vertices",
          "ring"
        ]
      },
      "ClosuresDto": {
        "type": "object",
        "properties": {
          "method": {
            "type": "string",
            "example": "dock_steppe.closures v1",
            "description": "The name and version of the rule that builds the list."
          },
          "source": {
            "type": "string",
            "example": "partner reports (POST /v1/closures)",
            "description": "Where the closures come from."
          },
          "as_of": {
            "type": "string",
            "example": "2026-10-02",
            "description": "Today, Ulaanbaatar calendar."
          },
          "current": {
            "type": "integer",
            "example": 1,
            "description": "How many closures count today."
          },
          "ids_sha256": {
            "type": "string",
            "nullable": true,
            "description": "sha256 of the sorted ids joined by commas; null for none. Compare with an offline pack's closures_sha256."
          },
          "buffer_m": {
            "type": "number",
            "example": 15,
            "description": "Metres added around a closed spot or stretch to make its ring."
          },
          "rule": {
            "type": "string",
            "description": "The rule in words."
          },
          "active_when": {
            "type": "string",
            "example": "from <= route day, and route day <= to when to is set",
            "description": "When a closure counts for a route day."
          },
          "valhalla_limits": {
            "type": "object",
            "example": {
              "perimeter_m": 10000,
              "vertices": 100
            },
            "description": "Per route request, all rings together."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClosureItemDto"
            },
            "description": "The closures that count today, in id order."
          }
        },
        "required": [
          "method",
          "source",
          "as_of",
          "current",
          "ids_sha256",
          "buffer_m",
          "rule",
          "active_when",
          "valhalla_limits",
          "items"
        ]
      },
      "ClosureGeometryDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Point",
              "LineString"
            ],
            "description": "Point for a closed spot, LineString for a closed stretch."
          },
          "coordinates": {
            "oneOf": [
              {
                "type": "array",
                "items": {
                  "type": "number"
                }
              },
              {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  }
                }
              }
            ],
            "example": [
              102.10018,
              46.79994
            ],
            "description": "Point: [lon, lat] on the stretch, not on a junction. LineString: 2 to 300 [lon, lat], at most 3000 m."
          }
        },
        "required": [
          "type",
          "coordinates"
        ]
      },
      "ClosureBodyDto": {
        "type": "object",
        "properties": {
          "geometry": {
            "$ref": "#/components/schemas/ClosureGeometryDto"
          },
          "kind": {
            "type": "string",
            "enum": [
              "flood",
              "washout",
              "bridge_out",
              "snow",
              "mud",
              "works",
              "other"
            ],
            "example": "flood"
          },
          "from": {
            "type": "string",
            "example": "2026-10-02",
            "description": "First closed day, Ulaanbaatar calendar. Default today."
          },
          "to": {
            "type": "string",
            "example": "2026-10-09",
            "nullable": true,
            "description": "Last closed day. Absent or null: until lifted."
          },
          "note": {
            "type": "string",
            "example": "Ford under 1 m of water after rain",
            "maxLength": 200,
            "description": "Your words for your own records; never served to others. No names, no phone numbers."
          }
        },
        "required": [
          "geometry",
          "kind"
        ]
      },
      "ClosureDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ],
            "description": "GeoJSON type, Feature."
          },
          "id": {
            "type": "string",
            "example": "cl-000001",
            "description": "Never reused."
          },
          "geometry": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ClosureGeometryDto"
              }
            ],
            "description": "Where the closure is: a Point or a LineString."
          },
          "properties": {
            "type": "object",
            "example": {
              "kind": "flood",
              "from": "2026-10-02",
              "to": null,
              "lifted": null,
              "note": "Ford under 1 m of water after rain",
              "confidence": 0.5,
              "reported_at": "2026-10-02T05:12:40Z"
            },
            "description": "As stored. lifted: open again from this day, set once."
          }
        },
        "required": [
          "type",
          "id",
          "geometry",
          "properties"
        ]
      },
      "ClosureLiftDto": {
        "type": "object",
        "properties": {
          "on": {
            "type": "string",
            "example": "2026-10-05",
            "description": "Open again from this day. Default today; never later than today."
          }
        }
      },
      "CleanBodyDto": {
        "type": "object",
        "properties": {
          "addresses": {
            "minItems": 1,
            "maxItems": 100,
            "example": [
              "ХУД, 11-р хороо, Их Монгол Улсын гудамж, Их монгол плаза, 1-р давхар"
            ],
            "description": "Raw address strings as your customers typed them, up to 300 characters each.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "addresses"
        ]
      },
      "CleanDistrictDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "khan_uul"
          },
          "name_mn": {
            "type": "string",
            "nullable": true,
            "example": "Хан-Уул"
          }
        },
        "required": [
          "code",
          "name_mn"
        ]
      },
      "CleanNumbersDto": {
        "type": "object",
        "properties": {
          "entrance": {
            "example": [
              3
            ],
            "description": "Entrance numbers. A gate with no number gives none.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "floor": {
            "example": [
              1
            ],
            "description": "Floors. A basement is negative: \"В1 давхар\" is -1.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "unit": {
            "example": [],
            "description": "Units. A range on one floor is spelt out: \"1206-1208 тоот\" gives three.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "pavilion": {
            "example": [],
            "description": "Market pavilion numbers (\"29-р павилион\").",
            "type": "array",
            "items": {
              "type": "number"
            }
          }
        },
        "required": [
          "entrance",
          "floor",
          "unit",
          "pavilion"
        ]
      },
      "CleanChoiceDto": {
        "type": "object",
        "properties": {
          "building_id": {
            "type": "string",
            "nullable": true,
            "format": "uuid",
            "description": "Building footprint. null when withheld."
          },
          "point": {
            "nullable": true,
            "example": [
              106.937742,
              47.889612
            ],
            "description": "[lon, lat], WGS84. null when withheld.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "district": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/CleanDistrictDto"
              }
            ]
          },
          "area": {
            "type": "string",
            "nullable": true,
            "example": "Сансар",
            "description": "Nearest area name within 1000 m. null when none or withheld."
          },
          "street": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "Nearest street name within 150 m. null when none or withheld."
          },
          "withheld": {
            "type": "boolean",
            "description": "true when the building is in a restricted site: only the district is given."
          }
        },
        "required": [
          "building_id",
          "point",
          "district",
          "area",
          "street",
          "withheld"
        ]
      },
      "CleanRowDto": {
        "type": "object",
        "properties": {
          "index": {
            "type": "number",
            "example": 0,
            "description": "Position in the request."
          },
          "official_address": {
            "nullable": true,
            "description": "null until a state address register is matched; a named door (method door_name) gives its own.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/OfficialAddressDto"
              }
            ]
          },
          "official_status": {
            "type": "string",
            "enum": [
              "matched",
              "partial",
              "none"
            ]
          },
          "unofficial": {
            "type": "boolean",
            "description": "true unless official_status is matched. Show \"unofficial\"."
          },
          "district": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/CleanDistrictDto"
              }
            ]
          },
          "khoroo": {
            "type": "integer",
            "nullable": true,
            "example": 11
          },
          "microdistrict": {
            "example": [],
            "description": "As typed, in the order found. Empty when absent.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "street": {
            "example": [
              "Их Монгол Улсын гудамж"
            ],
            "description": "As typed, in the order found. Empty when absent.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "building": {
            "example": [
              "Их монгол плаза"
            ],
            "description": "As typed, in the order found. Empty when absent.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "entrance": {
            "example": [],
            "description": "As typed, in the order found. Empty when absent.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "floor": {
            "example": [
              "1-р давхар"
            ],
            "description": "As typed, in the order found. Empty when absent.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "unit": {
            "example": [],
            "description": "As typed, in the order found. Empty when absent.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "landmark": {
            "example": [],
            "description": "As typed, in the order found. Empty when absent.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "numbers": {
            "description": "Entrance, floor, unit and pavilion as values. Empty lists when absent.",
            "allOf": [
              {
                "$ref": "#/components/schemas/CleanNumbersDto"
              }
            ]
          },
          "building_id": {
            "type": "string",
            "nullable": true,
            "format": "uuid",
            "description": "Matched building footprint. null when none was sure enough, and for a named gate on a plot."
          },
          "point": {
            "nullable": true,
            "example": [
              106.937742,
              47.889612
            ],
            "description": "[lon, lat], WGS84, a point on the building; a named door's entrance.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "method": {
            "type": "string",
            "nullable": true,
            "example": "name_street",
            "description": "How the building was found. door_name: the row is a door name."
          },
          "match_confidence": {
            "type": "number",
            "nullable": true,
            "minimum": 0,
            "maximum": 1,
            "example": 0.593,
            "description": "Share of test rows this method got right. Not a PLAN 5 level, not a promise per row. null with no building, and for a method with no test rows yet (number_area_ambiguous)."
          },
          "source": {
            "type": "string",
            "nullable": true,
            "example": "osm",
            "description": "Source of the building footprint."
          },
          "withheld": {
            "type": "boolean",
            "description": "true when the building is in a restricted site: building and point are withheld."
          },
          "remainder": {
            "type": "string",
            "example": "",
            "description": "Text the parser did not place in any field."
          },
          "choices": {
            "example": [],
            "description": "For method name_ambiguous, number_ambiguous or number_area_ambiguous: up to 3 places it could be, the answer first, each with its district and nearest area and street names. Empty for any other method.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CleanChoiceDto"
            }
          }
        },
        "required": [
          "index",
          "official_address",
          "official_status",
          "unofficial",
          "district",
          "khoroo",
          "microdistrict",
          "street",
          "building",
          "entrance",
          "floor",
          "unit",
          "landmark",
          "numbers",
          "building_id",
          "point",
          "method",
          "match_confidence",
          "source",
          "withheld",
          "remainder",
          "choices"
        ]
      },
      "CleanDto": {
        "type": "object",
        "properties": {
          "rows": {
            "description": "One row per address, request order.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CleanRowDto"
            }
          },
          "matched": {
            "type": "number",
            "example": 1,
            "description": "Rows with a building, or a named door."
          },
          "attribution": {
            "type": "string",
            "example": "© OpenStreetMap contributors; Overture Maps Foundation"
          }
        },
        "required": [
          "rows",
          "matched",
          "attribution"
        ]
      },
      "SignupBodyDto": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "example": "dev@example.com",
            "description": "The account's contact. Never logged or shown."
          },
          "name": {
            "type": "string",
            "example": "Түргэн хүргэлт ХХК",
            "description": "The company's name, 2 to 80 characters."
          }
        }
      },
      "SignupDto": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "example": "dk_0123456789abcdefghjkmnpqrstvwxyz",
            "description": "The key. Shown once, in this answer only: dock keeps its sha256, not the key."
          },
          "prefix": {
            "type": "string",
            "example": "dk_01234567",
            "description": "First 11 characters. Names the key in GET /v1/usage."
          },
          "plan": {
            "type": "string",
            "example": "free",
            "enum": [
              "free"
            ]
          },
          "scopes": {
            "example": [
              "door:read",
              "geocode:read",
              "route:read",
              "tiles:read"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rate_limit": {
            "type": "number",
            "example": 60,
            "description": "Requests per minute."
          },
          "tile_rate_limit": {
            "type": "number",
            "example": 600,
            "description": "Kept for older clients; not enforced since 0.78.0 (tiles have no per-minute limit)."
          },
          "caps": {
            "$ref": "#/components/schemas/UsageCapsDto"
          }
        },
        "required": [
          "key",
          "prefix",
          "plan",
          "scopes",
          "rate_limit",
          "tile_rate_limit",
          "caps"
        ]
      },
      "LimitsDto": {
        "type": "object",
        "properties": {
          "daily": {
            "type": "number",
            "nullable": true,
            "example": 1000,
            "description": "Calls a day for the whole company, all its keys together. null: no cap."
          },
          "tiles_daily": {
            "type": "number",
            "nullable": true,
            "example": 25000
          },
          "door_misses": {
            "type": "number",
            "nullable": true,
            "example": 50
          }
        },
        "required": [
          "daily",
          "tiles_daily",
          "door_misses"
        ]
      },
      "MemberDto": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "example": "driver@example.com"
          },
          "role": {
            "type": "string",
            "enum": [
              "owner",
              "admin",
              "developer",
              "driver"
            ]
          },
          "state": {
            "type": "string",
            "enum": [
              "invited",
              "active"
            ]
          },
          "invited_at": {
            "type": "string"
          }
        },
        "required": [
          "email",
          "role",
          "state",
          "invited_at"
        ]
      },
      "OrgDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Түргэн хүргэлт ХХК"
          },
          "plan": {
            "type": "string",
            "example": "free"
          },
          "limits": {
            "$ref": "#/components/schemas/LimitsDto"
          },
          "members": {
            "nullable": true,
            "description": "The company's people. null for a key without org:admin.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MemberDto"
            }
          },
          "keys": {
            "type": "number",
            "example": 3,
            "description": "Live keys of the company."
          }
        },
        "required": [
          "name",
          "plan",
          "limits",
          "members",
          "keys"
        ]
      },
      "KeyDto": {
        "type": "object",
        "properties": {
          "prefix": {
            "type": "string",
            "example": "dk_0123abcd"
          },
          "name": {
            "type": "string",
            "example": "checkout page"
          },
          "scopes": {
            "example": [
              "geocode:read"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "created_at": {
            "type": "string"
          },
          "revoked": {
            "type": "boolean"
          }
        },
        "required": [
          "prefix",
          "name",
          "scopes",
          "created_at",
          "revoked"
        ]
      },
      "KeysDto": {
        "type": "object",
        "properties": {
          "keys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KeyDto"
            }
          }
        },
        "required": [
          "keys"
        ]
      },
      "KeyBodyDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "checkout page",
            "description": "1 to 60 characters."
          },
          "scopes": {
            "example": [
              "geocode:read",
              "tiles:read"
            ],
            "description": "Some of your key's scopes. Left out: all of them but org:admin.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name"
        ]
      },
      "NewKeyDto": {
        "type": "object",
        "properties": {
          "prefix": {
            "type": "string",
            "example": "dk_0123abcd"
          },
          "name": {
            "type": "string",
            "example": "checkout page"
          },
          "scopes": {
            "example": [
              "geocode:read"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "created_at": {
            "type": "string"
          },
          "revoked": {
            "type": "boolean"
          },
          "key": {
            "type": "string",
            "example": "dk_0123456789abcdefghjkmnpqrstvwxyz",
            "description": "Shown once, in this answer only."
          }
        },
        "required": [
          "prefix",
          "name",
          "scopes",
          "created_at",
          "revoked",
          "key"
        ]
      },
      "InviteBodyDto": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "example": "driver@example.com"
          },
          "role": {
            "type": "string",
            "enum": [
              "admin",
              "developer",
              "driver"
            ]
          }
        },
        "required": [
          "email",
          "role"
        ]
      },
      "InviteDto": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "example": "driver@example.com"
          },
          "role": {
            "type": "string",
            "enum": [
              "admin",
              "developer",
              "driver"
            ]
          },
          "link": {
            "type": "string",
            "example": "https://dock.mn/account#invite=iv_...",
            "description": "Send it to the person yourself; dock sends no e-mail yet. One use, 7 days."
          }
        },
        "required": [
          "email",
          "role",
          "link"
        ]
      },
      "AcceptBodyDto": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "example": "iv_..."
          }
        },
        "required": [
          "token"
        ]
      },
      "AcceptDto": {
        "type": "object",
        "properties": {
          "org": {
            "type": "string",
            "example": "Түргэн хүргэлт ХХК"
          },
          "role": {
            "type": "string",
            "enum": [
              "admin",
              "developer",
              "driver"
            ]
          },
          "key": {
            "type": "string",
            "example": "dk_0123456789abcdefghjkmnpqrstvwxyz",
            "description": "The new member's own key, shown once."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "org",
          "role",
          "key",
          "scopes"
        ]
      },
      "ImportBodyDto": {
        "type": "object",
        "properties": {
          "sheet": {
            "type": "string",
            "example": "ref\taddress\tnote\nA-1\tСансар 24, 12 давхар, 1204 тоот\t",
            "description": "The sheet as text: a paste from a spreadsheet (tabs) or CSV."
          }
        },
        "required": [
          "sheet"
        ]
      },
      "ImportDto": {
        "type": "object",
        "properties": {
          "imported": {
            "type": "number",
            "example": 100
          },
          "located": {
            "type": "number",
            "example": 96
          },
          "unlocated": {
            "description": "Refs of the rows dock did not find: kept, never planned, fix the address.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "skipped": {
            "type": "number",
            "example": 0
          }
        },
        "required": [
          "imported",
          "located",
          "unlocated",
          "skipped"
        ]
      },
      "DeliveryDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "ref": {
            "type": "string",
            "example": "A-1"
          },
          "address": {
            "type": "string",
            "example": "Сансар 24"
          },
          "note": {
            "type": "string",
            "nullable": true
          },
          "point": {
            "nullable": true,
            "description": "Where dock found the address; null: unlocated, never planned.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "code": {
            "type": "string",
            "nullable": true,
            "example": "7QSVX"
          },
          "match": {
            "type": "string",
            "enum": [
              "door",
              "place",
              "point",
              "none"
            ]
          },
          "confidence": {
            "type": "number",
            "nullable": true,
            "example": 0.82
          },
          "status": {
            "type": "string",
            "enum": [
              "new",
              "assigned",
              "arrived",
              "delivered",
              "failed"
            ]
          },
          "driver": {
            "type": "string",
            "nullable": true,
            "example": "driver1@example.com"
          },
          "seq": {
            "type": "integer",
            "nullable": true
          },
          "eta": {
            "type": "string",
            "nullable": true
          },
          "tracked": {
            "type": "boolean"
          },
          "door_said": {
            "type": "boolean",
            "description": "The customer tapped \"энэ миний хаалга\" on the tracking link: their word for the door."
          }
        },
        "required": [
          "id",
          "ref",
          "address",
          "note",
          "point",
          "code",
          "match",
          "confidence",
          "status",
          "driver",
          "seq",
          "eta",
          "tracked",
          "door_said"
        ]
      },
      "DeliveriesDto": {
        "type": "object",
        "properties": {
          "deliveries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DeliveryDto"
            }
          }
        },
        "required": [
          "deliveries"
        ]
      },
      "PlanBodyDto": {
        "type": "object",
        "properties": {
          "depot": {
            "example": [
              106.9177,
              47.9186
            ],
            "description": "Where the drivers start and come back, lon,lat.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "drivers": {
            "description": "Drivers by e-mail. Left out: every driver of the company.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "depot"
        ]
      },
      "PlanDriverDto": {
        "type": "object",
        "properties": {
          "driver": {
            "type": "string"
          },
          "stops": {
            "type": "number"
          },
          "distance_m": {
            "type": "number"
          },
          "duration_s": {
            "type": "number"
          }
        },
        "required": [
          "driver",
          "stops",
          "distance_m",
          "duration_s"
        ]
      },
      "PlanDto": {
        "type": "object",
        "properties": {
          "drivers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlanDriverDto"
            }
          },
          "planned": {
            "type": "number"
          },
          "unlocated": {
            "type": "number"
          },
          "ms": {
            "type": "number"
          }
        },
        "required": [
          "drivers",
          "planned",
          "unlocated",
          "ms"
        ]
      },
      "ReassignBodyDto": {
        "type": "object",
        "properties": {
          "driver": {
            "type": "string",
            "example": "driver2@example.com",
            "description": "Give it to this driver."
          },
          "point": {
            "example": [
              106.9177,
              47.9186
            ],
            "description": "Put it here: the dispatcher's pick (a search box result), confidence 1.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "code": {
            "type": "string",
            "nullable": true,
            "example": "7QSVX",
            "description": "With point: the picked door's code."
          }
        }
      },
      "TrackLinkDto": {
        "type": "object",
        "properties": {
          "link": {
            "type": "string",
            "example": "https://dock.mn/t/tr_..."
          }
        },
        "required": [
          "link"
        ]
      },
      "TrackedDto": {
        "type": "object",
        "properties": {
          "ref": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "new",
              "assigned",
              "arrived",
              "delivered",
              "failed"
            ]
          },
          "eta": {
            "type": "string",
            "nullable": true
          },
          "point": {
            "nullable": true,
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "driver_at": {
            "nullable": true,
            "description": "The driver, only while your stop is their next one.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "driver_seen": {
            "type": "string",
            "nullable": true
          },
          "stops_before": {
            "type": "integer",
            "nullable": true,
            "description": "Stops the driver makes before yours."
          },
          "code": {
            "type": "string",
            "nullable": true,
            "description": "Your door's code, when the delivery is a door; tap \"энэ миний хаалга\" for it."
          },
          "door_said": {
            "type": "boolean",
            "description": "You already said this is your entrance."
          }
        },
        "required": [
          "ref",
          "status",
          "eta",
          "point",
          "driver_at",
          "driver_seen",
          "stops_before",
          "code",
          "door_said"
        ]
      },
      "DoorSaidDto": {
        "type": "object",
        "properties": {
          "state": {
            "type": "string",
            "enum": [
              "recorded",
              "already_recorded"
            ]
          }
        },
        "required": [
          "state"
        ]
      },
      "PositionDto": {
        "type": "object",
        "properties": {
          "driver": {
            "type": "string"
          },
          "point": {
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "accuracy_m": {
            "type": "number",
            "nullable": true
          },
          "at": {
            "type": "string"
          }
        },
        "required": [
          "driver",
          "point",
          "accuracy_m",
          "at"
        ]
      },
      "PositionsDto": {
        "type": "object",
        "properties": {
          "positions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PositionDto"
            }
          }
        },
        "required": [
          "positions"
        ]
      },
      "JobDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "ref": {
            "type": "string",
            "example": "A-1"
          },
          "address": {
            "type": "string",
            "example": "Сансар 24"
          },
          "note": {
            "type": "string",
            "nullable": true
          },
          "point": {
            "nullable": true,
            "description": "Where dock found the address; null: unlocated, never planned.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "code": {
            "type": "string",
            "nullable": true,
            "example": "7QSVX"
          },
          "match": {
            "type": "string",
            "enum": [
              "door",
              "place",
              "point",
              "none"
            ]
          },
          "confidence": {
            "type": "number",
            "nullable": true,
            "example": 0.82
          },
          "status": {
            "type": "string",
            "enum": [
              "new",
              "assigned",
              "arrived",
              "delivered",
              "failed"
            ]
          },
          "driver": {
            "type": "string",
            "nullable": true,
            "example": "driver1@example.com"
          },
          "seq": {
            "type": "integer",
            "nullable": true
          },
          "eta": {
            "type": "string",
            "nullable": true
          },
          "tracked": {
            "type": "boolean"
          },
          "door_said": {
            "type": "boolean",
            "description": "The customer tapped \"энэ миний хаалга\" on the tracking link: their word for the door."
          },
          "official_line": {
            "type": "string",
            "nullable": true,
            "example": "Хан-Уул дүүрэг, 1-р хороо, Шинэ өглөө хотхон, 23-р байр",
            "description": "The official address of the stop's code as one line; null when the stop has no code or none is known."
          },
          "name_mn": {
            "type": "string",
            "nullable": true,
            "example": "Хаан банк",
            "description": "The name of the building or place behind the code; null when none is known."
          },
          "stops_confirmed": {
            "type": "integer",
            "nullable": true,
            "example": 1,
            "description": "How many stops have confirmed this code's door, capped at 3, the number the door rule needs; null when the stop has no code."
          }
        },
        "required": [
          "id",
          "ref",
          "address",
          "note",
          "point",
          "code",
          "match",
          "confidence",
          "status",
          "driver",
          "seq",
          "eta",
          "tracked",
          "door_said",
          "official_line",
          "name_mn",
          "stops_confirmed"
        ]
      },
      "JobsDto": {
        "type": "object",
        "properties": {
          "deliveries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JobDto"
            }
          }
        },
        "required": [
          "deliveries"
        ]
      },
      "FixBodyDto": {
        "type": "object",
        "properties": {
          "lon": {
            "type": "number",
            "example": 106.9177
          },
          "lat": {
            "type": "number",
            "example": 47.9186
          },
          "accuracy": {
            "type": "number",
            "example": 8
          }
        },
        "required": [
          "lon",
          "lat"
        ]
      },
      "StatusBodyDto": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "arrived",
              "delivered",
              "failed"
            ]
          }
        },
        "required": [
          "status"
        ]
      },
      "StyleBodyDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Sansar Delivery",
            "description": "Up to 60 characters. Default \"dock\"."
          },
          "background": {
            "type": "string",
            "example": "#f4f1ea",
            "description": "Background color, #rrggbb."
          },
          "building": {
            "type": "string",
            "example": "#d9d3c7",
            "description": "Building fill, #rrggbb."
          },
          "building_outline": {
            "type": "string",
            "example": "#a39b8b",
            "description": "Building outline, #rrggbb."
          },
          "extrude": {
            "type": "boolean",
            "example": false,
            "description": "Extrude buildings by height. Default false."
          }
        }
      },
      "StyleSpecDto": {
        "type": "object",
        "properties": {
          "background": {
            "type": "string",
            "example": "#f4f1ea"
          },
          "building": {
            "type": "string",
            "example": "#d9d3c7"
          },
          "building_outline": {
            "type": "string",
            "example": "#a39b8b"
          },
          "extrude": {
            "type": "boolean",
            "example": false
          }
        },
        "required": [
          "background",
          "building",
          "building_outline",
          "extrude"
        ]
      },
      "StyleDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "st_7m4xq2b9kd",
            "description": "Style id. Pass it to createMap as styleId."
          },
          "name": {
            "type": "string",
            "example": "Sansar Delivery"
          },
          "spec": {
            "description": "Every option, defaults filled. Never changes for this id. A whole MapLibre style saved by dock.mn/studio shows here as {\"kind\": \"maplibre\"}; GET its url for the style.",
            "allOf": [
              {
                "$ref": "#/components/schemas/StyleSpecDto"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "example": "2026-10-01T11:24:38Z"
          },
          "url": {
            "type": "string",
            "example": "https://geo.dock.mn/v1/styles/st_7m4xq2b9kd",
            "description": "The MapLibre style."
          }
        },
        "required": [
          "id",
          "name",
          "spec",
          "created_at",
          "url"
        ]
      },
      "StyleListDto": {
        "type": "object",
        "properties": {
          "styles": {
            "description": "Current styles of your org, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StyleDto"
            }
          },
          "max": {
            "type": "number",
            "example": 100,
            "description": "Most styles an org may keep."
          }
        },
        "required": [
          "styles",
          "max"
        ]
      },
      "AlertBodyDto": {
        "type": "object",
        "properties": {
          "metric": {
            "type": "string",
            "enum": [
              "calls",
              "tiles",
              "door_misses"
            ],
            "example": "calls",
            "description": "Which of today's counters to watch."
          },
          "percent": {
            "type": "number",
            "example": 80,
            "description": "Share of the daily cap, 1 to 100. Default 80."
          },
          "webhook_url": {
            "type": "string",
            "example": "https://hooks.example.mn/dock",
            "description": "Optional. https, default port, a public host name. Gets one signed POST per firing."
          }
        },
        "required": [
          "metric"
        ]
      },
      "AlertCreatedDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "al_7m4xq2b9kd",
            "description": "Alert id. Never reused."
          },
          "metric": {
            "type": "string",
            "enum": [
              "calls",
              "tiles",
              "door_misses"
            ],
            "example": "calls"
          },
          "percent": {
            "type": "number",
            "example": 80
          },
          "webhook_url": {
            "type": "string",
            "nullable": true,
            "example": "https://hooks.example.mn/dock"
          },
          "created_at": {
            "type": "string",
            "example": "2026-10-01T11:24:38Z"
          },
          "webhook_secret": {
            "type": "string",
            "nullable": true,
            "example": "whsec_0123456789abcdefghjkmnpqrstvwx",
            "description": "Checks the Dock-Signature header of each webhook. Shown only here, once. null with no webhook."
          }
        },
        "required": [
          "id",
          "metric",
          "percent",
          "webhook_url",
          "created_at",
          "webhook_secret"
        ]
      },
      "AlertDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "al_7m4xq2b9kd",
            "description": "Alert id. Never reused."
          },
          "metric": {
            "type": "string",
            "enum": [
              "calls",
              "tiles",
              "door_misses"
            ],
            "example": "calls"
          },
          "percent": {
            "type": "number",
            "example": 80
          },
          "webhook_url": {
            "type": "string",
            "nullable": true,
            "example": "https://hooks.example.mn/dock"
          },
          "created_at": {
            "type": "string",
            "example": "2026-10-01T11:24:38Z"
          }
        },
        "required": [
          "id",
          "metric",
          "percent",
          "webhook_url",
          "created_at"
        ]
      },
      "AlertEventDto": {
        "type": "object",
        "properties": {
          "alert": {
            "type": "string",
            "example": "al_7m4xq2b9kd"
          },
          "metric": {
            "type": "string",
            "example": "calls"
          },
          "percent": {
            "type": "number",
            "example": 80
          },
          "day": {
            "type": "string",
            "example": "2026-10-01",
            "description": "Ulaanbaatar day."
          },
          "value": {
            "type": "number",
            "example": 8004,
            "description": "The counter when the alert fired."
          },
          "cap": {
            "type": "number",
            "example": 10000,
            "description": "The daily cap then."
          },
          "fired_at": {
            "type": "string",
            "example": "2026-10-01T06:12:00Z"
          },
          "delivery": {
            "type": "string",
            "enum": [
              "none",
              "pending",
              "sent",
              "failed"
            ],
            "description": "Webhook delivery. none: no webhook."
          },
          "http_status": {
            "type": "number",
            "nullable": true,
            "example": 200,
            "description": "Last webhook answer; null if none came."
          }
        },
        "required": [
          "alert",
          "metric",
          "percent",
          "day",
          "value",
          "cap",
          "fired_at",
          "delivery",
          "http_status"
        ]
      },
      "AlertListDto": {
        "type": "object",
        "properties": {
          "alerts": {
            "description": "Current alerts of your org, oldest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AlertDto"
            }
          },
          "events": {
            "description": "Firings of the last 30 Ulaanbaatar days, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AlertEventDto"
            }
          },
          "max": {
            "type": "number",
            "example": 20,
            "description": "Most alerts an org may keep."
          },
          "check_seconds": {
            "type": "number",
            "example": 60,
            "description": "Seconds between checks. An alert fires within about this long."
          }
        },
        "required": [
          "alerts",
          "events",
          "max",
          "check_seconds"
        ]
      },
      "SearchPickDto": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "door",
              "business",
              "building",
              "landmark",
              "district",
              "khoroo",
              "area",
              "street"
            ],
            "example": "door",
            "description": "kind of the picked result, as GET /v1/geocode gave it"
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "example": "01a0f5aa-e014-78ba-a622-8c41cd37fc68",
            "description": "id of the picked result"
          },
          "rank": {
            "type": "number",
            "minimum": 1,
            "maximum": 20,
            "example": 1,
            "description": "1 = the first result shown"
          }
        },
        "required": [
          "kind",
          "id",
          "rank"
        ]
      },
      "SearchEventDto": {
        "type": "object",
        "properties": {
          "q": {
            "type": "string",
            "maxLength": 200,
            "example": "Сансар 24",
            "description": "What the user typed into the place search, final text."
          },
          "results": {
            "type": "number",
            "minimum": 0,
            "maximum": 20,
            "example": 5,
            "description": "How many results were shown."
          },
          "picked": {
            "nullable": true,
            "description": "What the user picked; null or absent if nothing.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/SearchPickDto"
              }
            ]
          }
        },
        "required": [
          "q",
          "results"
        ]
      },
      "SearchTelemetryBodyDto": {
        "type": "object",
        "properties": {
          "consent": {
            "type": "string",
            "enum": [
              "opt_in"
            ],
            "example": "opt_in",
            "description": "Send only after the user opted in. Anything else is 400 consent_required."
          },
          "client": {
            "type": "string",
            "enum": [
              "sdk",
              "api"
            ],
            "example": "sdk",
            "description": "Default api."
          },
          "events": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SearchEventDto"
            }
          }
        },
        "required": [
          "consent",
          "events"
        ]
      },
      "SearchTelemetryDto": {
        "type": "object",
        "properties": {
          "stored": {
            "type": "integer",
            "example": 2,
            "description": "Events stored."
          },
          "dropped": {
            "type": "integer",
            "example": 1,
            "description": "Events not stored: text that was only a phone number or an e-mail address, or a pick not in the index."
          }
        },
        "required": [
          "stored",
          "dropped"
        ]
      },
      "TraceBodyDto": {
        "type": "object",
        "properties": {
          "format": {
            "type": "string",
            "enum": [
              "dock.trace.v1"
            ],
            "example": "dock.trace.v1"
          },
          "consent": {
            "type": "string",
            "enum": [
              "opt_in"
            ],
            "example": "opt_in",
            "description": "Send only after the user said yes. Anything else is 400 consent_required."
          },
          "points": {
            "type": "array",
            "minItems": 2,
            "maxItems": 20000,
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 3,
              "maxItems": 3
            },
            "example": [
              [
                102.71541,
                47.10125,
                1790812800
              ],
              [
                102.71563,
                47.10141,
                1790812805
              ]
            ],
            "description": "[lon, lat, t]: WGS84 degrees and whole seconds UTC, inside Mongolia. Nothing else per point."
          }
        },
        "required": [
          "format",
          "consent",
          "points"
        ]
      },
      "TraceStoredDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Keep it to fetch or delete the trace. null: nothing was stored."
          },
          "points": {
            "type": "integer",
            "example": 2,
            "description": "Points in the upload."
          },
          "restricted": {
            "type": "integer",
            "example": 0,
            "description": "Points left out: inside a restricted site (military, border, prison, power)."
          },
          "duplicate": {
            "type": "boolean",
            "example": false,
            "description": "This trip was sent before by your organization; id is the first upload."
          },
          "purge_after": {
            "type": "string",
            "example": "2026-12-30",
            "nullable": true,
            "description": "Raw points are erased after this day (90 days)."
          }
        },
        "required": [
          "id",
          "points",
          "restricted",
          "duplicate",
          "purge_after"
        ]
      },
      "TraceCellDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "id": {
            "type": "string",
            "example": "18215/7623",
            "description": "x/y of the cell in the fixed grid; the same cell every month"
          },
          "geometry": {
            "type": "object",
            "example": {
              "type": "Polygon",
              "coordinates": [
                [
                  [
                    106.9,
                    47.9
                  ],
                  [
                    106.9067,
                    47.9
                  ],
                  [
                    106.9067,
                    47.9045
                  ],
                  [
                    106.9,
                    47.9045
                  ],
                  [
                    106.9,
                    47.9
                  ]
                ]
              ]
            }
          },
          "properties": {
            "type": "object",
            "example": {
              "trips": 12
            },
            "description": "trips: distinct trips through the cell that month, all partners"
          }
        },
        "required": [
          "type",
          "id",
          "geometry",
          "properties"
        ]
      },
      "TraceCellsDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ]
          },
          "month": {
            "type": "string",
            "example": "2026-09"
          },
          "rule": {
            "type": "object",
            "description": "A cell is shown only when it meets this rule; any other cell is left out, not zero."
          },
          "features": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceCellDto"
            }
          }
        },
        "required": [
          "type",
          "month",
          "rule",
          "features"
        ]
      },
      "TraceSpeedDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "id": {
            "type": "string",
            "example": "18215/7623",
            "description": "x/y of the cell in the fixed grid, the same as GET /v1/traces/cells"
          },
          "geometry": {
            "type": "object",
            "example": {
              "type": "Polygon",
              "coordinates": [
                [
                  [
                    106.9,
                    47.9
                  ],
                  [
                    106.9067,
                    47.9
                  ],
                  [
                    106.9067,
                    47.9045
                  ],
                  [
                    106.9,
                    47.9045
                  ],
                  [
                    106.9,
                    47.9
                  ]
                ]
              ]
            }
          },
          "properties": {
            "type": "object",
            "example": {
              "km_h": 17.4
            },
            "description": "km_h: moving speed of all partners' trips in the cell that month, to 0.1; no trip count"
          }
        },
        "required": [
          "type",
          "id",
          "geometry",
          "properties"
        ]
      },
      "TraceSpeedsDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ]
          },
          "month": {
            "type": "string",
            "example": "2026-09"
          },
          "rule": {
            "type": "object",
            "description": "The group rule each cell passed, and how speed is measured; any other cell is left out, not slow"
          },
          "features": {
            "description": "cells north to south, then west to east",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceSpeedDto"
            }
          }
        },
        "required": [
          "type",
          "month",
          "rule",
          "features"
        ]
      },
      "TraceRoadDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "id": {
            "type": "string",
            "example": "28116000",
            "description": "the OSM way id, as text: it can pass 2^53 one day"
          },
          "geometry": {
            "type": "object",
            "example": {
              "type": "LineString",
              "coordinates": [
                [
                  106.917,
                  47.9185
                ],
                [
                  106.9203,
                  47.9184
                ]
              ]
            },
            "description": "dock's current road line with this OSM id; LineString, or MultiLineString when it is in pieces"
          },
          "properties": {
            "type": "object",
            "example": {
              "km_h": 23.6,
              "name_mn": "Энхтайваны өргөн чөлөө",
              "name_en": "Peace Avenue",
              "highway": "primary"
            },
            "description": "km_h: moving speed of all partners' trips on the way that month, to 0.1; no trip count. name_mn, name_en, highway: the road's, null when unknown"
          }
        },
        "required": [
          "type",
          "id",
          "geometry",
          "properties"
        ]
      },
      "TraceRoadsDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ]
          },
          "month": {
            "type": "string",
            "example": "2026-09"
          },
          "rule": {
            "type": "object",
            "description": "The group rule each road passed, and how it is matched and measured; any other road is left out, not slow"
          },
          "features": {
            "description": "roads by OSM way id, smallest first",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceRoadDto"
            }
          }
        },
        "required": [
          "type",
          "month",
          "rule",
          "features"
        ]
      },
      "TraceOwnCellDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "id": {
            "type": "string",
            "example": "18215/7623",
            "description": "x/y of the cell in the fixed grid, the same as GET /v1/traces/cells"
          },
          "geometry": {
            "type": "object",
            "example": {
              "type": "Polygon",
              "coordinates": [
                [
                  [
                    106.9,
                    47.9
                  ],
                  [
                    106.9067,
                    47.9
                  ],
                  [
                    106.9067,
                    47.9045
                  ],
                  [
                    106.9,
                    47.9045
                  ],
                  [
                    106.9,
                    47.9
                  ]
                ]
              ]
            }
          },
          "properties": {
            "type": "object",
            "example": {
              "trips": 3
            },
            "description": "trips: your distinct trips through the cell that month"
          }
        },
        "required": [
          "type",
          "id",
          "geometry",
          "properties"
        ]
      },
      "TraceOwnCellsDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ]
          },
          "month": {
            "type": "string",
            "example": "2026-10"
          },
          "closed": {
            "type": "boolean",
            "description": "false while trips received now still count; true from 14 days after the month ends"
          },
          "rule": {
            "type": "object",
            "description": "Your organization only, every cell with one of your trips. No cell means none of yours."
          },
          "features": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceOwnCellDto"
            }
          }
        },
        "required": [
          "type",
          "month",
          "closed",
          "rule",
          "features"
        ]
      },
      "TraceArrivalMinuteDto": {
        "type": "object",
        "properties": {
          "minutes": {
            "type": "integer",
            "example": 2,
            "description": "whole minutes; 60 is 60 or more"
          },
          "trips": {
            "type": "integer",
            "example": 14
          }
        },
        "required": [
          "minutes",
          "trips"
        ]
      },
      "TraceArrivalCellPropertiesDto": {
        "type": "object",
        "properties": {
          "trips": {
            "type": "integer",
            "example": 6,
            "description": "your trips that ended in the cell that month"
          },
          "slow": {
            "type": "integer",
            "example": 3,
            "description": "of them, arrivals of 5 minutes or more"
          },
          "median": {
            "type": "integer",
            "example": 4,
            "description": "median arrival minutes in the cell, nearest rank"
          }
        },
        "required": [
          "trips",
          "slow",
          "median"
        ]
      },
      "TraceArrivalCellDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "id": {
            "type": "string",
            "example": "18215/7623",
            "description": "x/y of the cell in the fixed grid, the same as GET /v1/traces/cells"
          },
          "geometry": {
            "type": "object",
            "example": {
              "type": "Polygon",
              "coordinates": [
                [
                  [
                    106.9,
                    47.9
                  ],
                  [
                    106.9067,
                    47.9
                  ],
                  [
                    106.9067,
                    47.9045
                  ],
                  [
                    106.9,
                    47.9045
                  ],
                  [
                    106.9,
                    47.9
                  ]
                ]
              ]
            }
          },
          "properties": {
            "$ref": "#/components/schemas/TraceArrivalCellPropertiesDto"
          }
        },
        "required": [
          "type",
          "id",
          "geometry",
          "properties"
        ]
      },
      "TraceArrivalsDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ]
          },
          "month": {
            "type": "string",
            "example": "2026-10"
          },
          "closed": {
            "type": "boolean",
            "description": "false while trips received now still count; true from 14 days after the month ends"
          },
          "rule": {
            "type": "object",
            "description": "How arrival minutes are measured. Your organization only."
          },
          "trips": {
            "type": "integer",
            "example": 41,
            "description": "your trips with an arrival that month, every cell"
          },
          "slow": {
            "type": "integer",
            "example": 9,
            "description": "of them, arrivals of 5 minutes or more"
          },
          "median": {
            "type": "integer",
            "example": 2,
            "nullable": true,
            "description": "nearest rank; null with no trips"
          },
          "p75": {
            "type": "integer",
            "example": 4,
            "nullable": true
          },
          "p90": {
            "type": "integer",
            "example": 7,
            "nullable": true
          },
          "histogram": {
            "description": "trips per arrival minute, minutes with none left out",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceArrivalMinuteDto"
            }
          },
          "cells": {
            "type": "integer",
            "example": 17,
            "description": "cells your trips ended in; features lists up to 100 of them"
          },
          "features": {
            "description": "cells by slow trips, then trips, most first; up to 100",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceArrivalCellDto"
            }
          }
        },
        "required": [
          "type",
          "month",
          "closed",
          "rule",
          "trips",
          "slow",
          "median",
          "p75",
          "p90",
          "histogram",
          "cells",
          "features"
        ]
      },
      "TraceHourSlotDto": {
        "type": "object",
        "properties": {
          "weekday": {
            "type": "integer",
            "example": 1,
            "description": "ISO weekday in Ulaanbaatar, 1 Monday to 7 Sunday"
          },
          "hour": {
            "type": "integer",
            "example": 9,
            "description": "hour in Ulaanbaatar, 0 to 23"
          },
          "trips": {
            "type": "integer",
            "example": 6,
            "description": "your trips that started in this weekday and hour that month"
          }
        },
        "required": [
          "weekday",
          "hour",
          "trips"
        ]
      },
      "TraceHoursDto": {
        "type": "object",
        "properties": {
          "month": {
            "type": "string",
            "example": "2026-10"
          },
          "closed": {
            "type": "boolean",
            "description": "false while trips received now still count; true from 14 days after the month ends"
          },
          "rule": {
            "type": "object",
            "description": "How the weekday and hour are read. Your organization only."
          },
          "trips": {
            "type": "integer",
            "example": 41,
            "description": "your trips that month"
          },
          "by_weekday": {
            "example": [
              8,
              7,
              6,
              6,
              9,
              4,
              1
            ],
            "description": "7 counts, Monday first",
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "by_hour": {
            "description": "24 counts, hour 0 first",
            "example": [
              0,
              0,
              0,
              0,
              0,
              0,
              0,
              1,
              3,
              5,
              4,
              3,
              4,
              4,
              3,
              3,
              4,
              3,
              2,
              1,
              1,
              0,
              0,
              0
            ],
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "slots": {
            "description": "weekday and hour with trips, weekday then hour; none left out",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceHourSlotDto"
            }
          }
        },
        "required": [
          "month",
          "closed",
          "rule",
          "trips",
          "by_weekday",
          "by_hour",
          "slots"
        ]
      },
      "TraceAllHourSlotDto": {
        "type": "object",
        "properties": {
          "weekday": {
            "type": "integer",
            "example": 1,
            "description": "ISO weekday in Ulaanbaatar, 1 Monday to 7 Sunday"
          },
          "hour": {
            "type": "integer",
            "example": 9,
            "description": "hour in Ulaanbaatar, 0 to 23"
          },
          "trips": {
            "type": "integer",
            "example": 212,
            "description": "trips from all partners that started in this weekday and hour that month"
          }
        },
        "required": [
          "weekday",
          "hour",
          "trips"
        ]
      },
      "TraceAllHoursDto": {
        "type": "object",
        "properties": {
          "month": {
            "type": "string",
            "example": "2026-09"
          },
          "rule": {
            "type": "object",
            "description": "The group rule each weekday and hour passed, and how they are read"
          },
          "slots": {
            "description": "weekday and hour that passed the rule, weekday then hour; a slot left out had too few trips, not zero; no total",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceAllHourSlotDto"
            }
          }
        },
        "required": [
          "month",
          "rule",
          "slots"
        ]
      },
      "TraceKhorooHourDto": {
        "type": "object",
        "properties": {
          "hour": {
            "type": "integer",
            "example": 18,
            "description": "hour in Ulaanbaatar of the trip end, 0 to 23"
          },
          "trips": {
            "type": "integer",
            "example": 37,
            "description": "trips from all partners that ended in this khoroo in this hour that month"
          }
        },
        "required": [
          "hour",
          "trips"
        ]
      },
      "TraceKhorooPropertiesDto": {
        "type": "object",
        "properties": {
          "district_mn": {
            "type": "string",
            "example": "Баянзүрх"
          },
          "district_en": {
            "type": "string",
            "example": "Bayanzurkh",
            "nullable": true
          },
          "khoroo": {
            "type": "integer",
            "example": 12,
            "description": "khoroo number in its district"
          },
          "hours": {
            "description": "hours that passed the rule, from 0; an hour left out had too few trips, not zero; no khoroo total",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceKhorooHourDto"
            }
          }
        },
        "required": [
          "district_mn",
          "district_en",
          "khoroo",
          "hours"
        ]
      },
      "TraceKhorooDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "id of the khoroo polygon; never an address"
          },
          "geometry": {
            "type": "object",
            "example": {
              "type": "MultiPolygon",
              "coordinates": [
                [
                  [
                    [
                      106.9,
                      47.9
                    ],
                    [
                      106.92,
                      47.9
                    ],
                    [
                      106.92,
                      47.91
                    ],
                    [
                      106.9,
                      47.9
                    ]
                  ]
                ]
              ]
            }
          },
          "properties": {
            "$ref": "#/components/schemas/TraceKhorooPropertiesDto"
          }
        },
        "required": [
          "type",
          "id",
          "geometry",
          "properties"
        ]
      },
      "TraceKhoroosDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ]
          },
          "month": {
            "type": "string",
            "example": "2026-09"
          },
          "rule": {
            "type": "object",
            "description": "The group rule each khoroo and hour passed, and how they are read"
          },
          "features": {
            "description": "khoroos with at least one hour shown, by district then number",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceKhorooDto"
            }
          }
        },
        "required": [
          "type",
          "month",
          "rule",
          "features"
        ]
      },
      "TraceOwnKhorooPropertiesDto": {
        "type": "object",
        "properties": {
          "district_mn": {
            "type": "string",
            "example": "Баянзүрх"
          },
          "district_en": {
            "type": "string",
            "example": "Bayanzurkh",
            "nullable": true
          },
          "khoroo": {
            "type": "integer",
            "example": 12,
            "description": "khoroo number in its district"
          },
          "trips": {
            "type": "integer",
            "example": 23,
            "description": "your trips that ended in this khoroo that month"
          },
          "hours": {
            "description": "your trips per hour of arrival, from 0; hours with none left out",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceKhorooHourDto"
            }
          }
        },
        "required": [
          "district_mn",
          "district_en",
          "khoroo",
          "trips",
          "hours"
        ]
      },
      "TraceOwnKhorooDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "id of the khoroo polygon; never an address"
          },
          "geometry": {
            "type": "object",
            "example": {
              "type": "MultiPolygon",
              "coordinates": [
                [
                  [
                    [
                      106.9,
                      47.9
                    ],
                    [
                      106.92,
                      47.9
                    ],
                    [
                      106.92,
                      47.91
                    ],
                    [
                      106.9,
                      47.9
                    ]
                  ]
                ]
              ]
            }
          },
          "properties": {
            "$ref": "#/components/schemas/TraceOwnKhorooPropertiesDto"
          }
        },
        "required": [
          "type",
          "id",
          "geometry",
          "properties"
        ]
      },
      "TraceOwnKhoroosDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ]
          },
          "month": {
            "type": "string",
            "example": "2026-10"
          },
          "closed": {
            "type": "boolean",
            "description": "false while trips received now still count; true from 14 days after the month ends"
          },
          "rule": {
            "type": "object",
            "description": "How the khoroo and hour are read. Your organization only."
          },
          "trips": {
            "type": "integer",
            "example": 41,
            "description": "your trips that month"
          },
          "no_khoroo": {
            "type": "integer",
            "example": 18,
            "description": "your trips that month ending in no current khoroo polygon; trips is no_khoroo plus every khoroo's trips"
          },
          "features": {
            "description": "khoroos with at least one of your trips, by district then number",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceOwnKhorooDto"
            }
          }
        },
        "required": [
          "type",
          "month",
          "closed",
          "rule",
          "trips",
          "no_khoroo",
          "features"
        ]
      },
      "TraceKindDto": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "apartment",
              "ger_house",
              "commercial",
              "public",
              "industrial",
              "garage",
              "other",
              "unknown",
              "none"
            ],
            "example": "apartment",
            "description": "building type at the trip end; unknown: a building with no type yet; none: no building within 30 m"
          },
          "trips": {
            "type": "integer",
            "example": 23,
            "description": "your trips that month ending at this kind of building"
          }
        },
        "required": [
          "kind",
          "trips"
        ]
      },
      "TraceKindsDto": {
        "type": "object",
        "properties": {
          "month": {
            "type": "string",
            "example": "2026-10"
          },
          "closed": {
            "type": "boolean",
            "description": "false while trips received now still count; true from 14 days after the month ends"
          },
          "rule": {
            "type": "object",
            "description": "How the building and its kind are read. Your organization only."
          },
          "trips": {
            "type": "integer",
            "example": 41,
            "description": "your trips that month; the sum of every kind's trips"
          },
          "kinds": {
            "description": "kinds with at least one of your trips, most trips first, then by name",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TraceKindDto"
            }
          }
        },
        "required": [
          "month",
          "closed",
          "rule",
          "trips",
          "kinds"
        ]
      },
      "TraceLineDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "LineString"
            ]
          },
          "coordinates": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              }
            },
            "description": "[lon, lat, t] as stored"
          }
        },
        "required": [
          "type",
          "coordinates"
        ]
      },
      "TraceDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "geometry": {
            "nullable": true,
            "description": "null once deleted or past purge_after",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/TraceLineDto"
              }
            ]
          },
          "properties": {
            "type": "object",
            "example": {
              "received_day": "2026-10-01",
              "purge_after": "2026-12-30",
              "points": 2,
              "restricted": 0,
              "deleted_at": null,
              "deleted_reason": null
            }
          }
        },
        "required": [
          "type",
          "id",
          "geometry",
          "properties"
        ]
      },
      "TraceDeletedDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "deleted": {
            "type": "boolean",
            "example": true,
            "description": "true: the points are gone. Also true when they were gone before."
          }
        },
        "required": [
          "id",
          "deleted"
        ]
      },
      "ProbeBodyDto": {
        "type": "object",
        "properties": {
          "format": {
            "type": "string",
            "enum": [
              "dock.probe.v1"
            ],
            "example": "dock.probe.v1"
          },
          "vehicle": {
            "type": "string",
            "example": "q3v9x0c2m8k4t7wz",
            "minLength": 16,
            "maxLength": 64,
            "pattern": "^[A-Za-z0-9_-]{16,64}$",
            "description": "A random token the app makes anew every 15 minutes, so dock can tell vehicles apart in one window and never across windows. Never a plate, phone or device id."
          },
          "points": {
            "type": "array",
            "minItems": 2,
            "maxItems": 900,
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 3,
              "maxItems": 3
            },
            "example": [
              [
                106.9177,
                47.9186,
                1791090000
              ],
              [
                106.9183,
                47.9186,
                1791090005
              ]
            ],
            "description": "[lon, lat, t]: WGS84 degrees and whole seconds UTC, inside Mongolia, t rising, within the last hour. Nothing else per point."
          }
        },
        "required": [
          "format",
          "vehicle",
          "points"
        ]
      },
      "ProbedDto": {
        "type": "object",
        "properties": {
          "points": {
            "type": "number",
            "example": 2,
            "description": "Points in the batch."
          },
          "restricted": {
            "type": "number",
            "example": 0,
            "description": "Points left out: inside a restricted site."
          },
          "roads": {
            "type": "number",
            "example": 1,
            "description": "Road and 15-minute window sums taken."
          },
          "late": {
            "type": "number",
            "example": 0,
            "description": "Road and window sums left out because their window had closed (5 minutes after it ended)."
          }
        },
        "required": [
          "points",
          "restricted",
          "roads",
          "late"
        ]
      },
      "TrafficTypicalNowDto": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "example": "ердийн",
            "description": "the word to show beside the speeds"
          },
          "band": {
            "type": "string",
            "example": "pm_peak",
            "description": "the hour band of this moment, Ulaanbaatar clock"
          },
          "hours": {
            "type": "string",
            "example": "Monday to Friday, 17:00 to 19:59 Ulaanbaatar time",
            "description": "The days and hours of the band, Ulaanbaatar clock, in words."
          },
          "month": {
            "type": "string",
            "nullable": true,
            "example": "2026-09",
            "description": "the closed month the speeds come from; null when no road has a speed"
          }
        },
        "required": [
          "label",
          "band",
          "hours",
          "month"
        ]
      },
      "TrafficTypicalRoadDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ],
            "description": "GeoJSON type, Feature."
          },
          "id": {
            "type": "string",
            "example": "28116000",
            "description": "the OSM way id, as text"
          },
          "geometry": {
            "type": "object",
            "example": {
              "type": "LineString",
              "coordinates": [
                [
                  106.917,
                  47.9185
                ],
                [
                  106.9203,
                  47.9184
                ]
              ]
            },
            "description": "dock's current road line with this OSM id"
          },
          "properties": {
            "type": "object",
            "example": {
              "km_h": 18.4,
              "name_mn": "Энхтайваны өргөн чөлөө",
              "name_en": "Peace Avenue",
              "highway": "primary"
            },
            "description": "km_h: the usual moving speed on the way in this band, to 0.1; name_mn, name_en, highway: the road's, null when unknown"
          }
        },
        "required": [
          "type",
          "id",
          "geometry",
          "properties"
        ]
      },
      "TrafficTypicalNowAnswerDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ],
            "description": "GeoJSON type, FeatureCollection."
          },
          "kind": {
            "type": "string",
            "enum": [
              "typical"
            ],
            "description": "always typical: never live"
          },
          "typical": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TrafficTypicalNowDto"
              }
            ],
            "description": "The label to show (\"ердийн\", usual), the hour band of this moment, and the month the speeds come from."
          },
          "rule": {
            "type": "object",
            "description": "The rule each road passed; any other road is left out: too few trips, not an empty road"
          },
          "source": {
            "type": "string",
            "example": "trace",
            "description": "Where the speeds come from: partner traces, all partners together."
          },
          "source_date": {
            "type": "string",
            "nullable": true,
            "example": "2026-09-30",
            "description": "the last day of the month the speeds come from; null when no road has a speed"
          },
          "features": {
            "description": "roads by OSM way id; empty is valid: no traces, no speed",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrafficTypicalRoadDto"
            }
          }
        },
        "required": [
          "type",
          "kind",
          "typical",
          "rule",
          "source",
          "source_date",
          "features"
        ]
      },
      "TrafficTypicalDto": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "example": "ердийн",
            "description": "the word to show beside the speeds"
          },
          "band": {
            "type": "string",
            "example": "pm_peak",
            "description": "the hour band of this moment, as GET /v1/traces/roads band"
          },
          "hours": {
            "type": "string",
            "example": "Monday to Friday, 17:00 to 19:59 Ulaanbaatar time",
            "description": "The days and hours of the band, Ulaanbaatar clock, in words."
          },
          "month": {
            "type": "string",
            "example": "2026-09",
            "description": "the closed month the speeds come from"
          }
        },
        "required": [
          "label",
          "band",
          "hours",
          "month"
        ]
      },
      "TrafficRoadDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ],
            "description": "GeoJSON type, Feature."
          },
          "id": {
            "type": "string",
            "example": "28116000",
            "description": "the OSM way id, as text"
          },
          "geometry": {
            "type": "object",
            "example": {
              "type": "LineString",
              "coordinates": [
                [
                  106.917,
                  47.9185
                ],
                [
                  106.9203,
                  47.9184
                ]
              ]
            },
            "description": "dock's current road line with this OSM id"
          },
          "properties": {
            "type": "object",
            "example": {
              "km_h": 18.4,
              "vehicles": 7,
              "name_mn": "Энхтайваны өргөн чөлөө",
              "name_en": "Peace Avenue",
              "highway": "primary"
            },
            "description": "km_h: moving speed of the vehicles on the way in the window, to 0.1; vehicles: how many, 5 or more, null when typical; name_mn, name_en, highway: the road's, null when unknown"
          }
        },
        "required": [
          "type",
          "id",
          "geometry",
          "properties"
        ]
      },
      "TrafficDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ],
            "description": "GeoJSON type, FeatureCollection."
          },
          "kind": {
            "type": "string",
            "enum": [
              "live",
              "typical"
            ],
            "description": "live: fleet probes of the last ended window; typical: no live road passed the rule, the speeds are the usual ones for this hour band"
          },
          "typical": {
            "nullable": true,
            "description": "null when live; when typical, the label to show, the hour band of this moment and the closed month the speeds come from",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/TrafficTypicalDto"
              }
            ]
          },
          "window": {
            "type": "object",
            "nullable": true,
            "example": {
              "from": "2026-10-13T12:30:00.000Z",
              "to": "2026-10-13T12:45:00.000Z"
            },
            "description": "the 15-minute window, the last that has ended; null when typical"
          },
          "rule": {
            "type": "object",
            "description": "The rule each road passed; any other road is left out: too few vehicles, not an empty road"
          },
          "source": {
            "type": "string",
            "example": "trace",
            "description": "Where the speeds come from: partner fleet traces."
          },
          "source_date": {
            "type": "string",
            "example": "2026-10-13",
            "description": "live: the date the window ended; typical: the last day of the month the speeds come from."
          },
          "features": {
            "description": "roads by OSM way id, smallest first",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrafficRoadDto"
            }
          }
        },
        "required": [
          "type",
          "kind",
          "typical",
          "window",
          "rule",
          "source",
          "source_date",
          "features"
        ]
      },
      "EventBodyDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Улаанбаатар марафон 2027",
            "minLength": 1,
            "maxLength": 120,
            "description": "The event's name. Never a person's."
          },
          "bbox": {
            "minItems": 4,
            "maxItems": 4,
            "example": [
              106.85,
              47.88,
              106.98,
              47.93
            ],
            "description": "[west, south, east, north]: the event's area, inside Mongolia, sides at most 1 degree. Points outside it are not stored.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "starts_at": {
            "type": "string",
            "example": "2027-06-12T08:00:00+08:00",
            "description": "ISO time with a zone. Points before it are not stored."
          },
          "ends_at": {
            "type": "string",
            "example": "2027-06-12T14:00:00+08:00",
            "description": "ISO time with a zone, after starts_at and after now, at most 14 days after starts_at. Points after it are not stored; 15 minutes after it every point is erased and only the heat cells stay."
          }
        },
        "required": [
          "name",
          "bbox",
          "starts_at",
          "ends_at"
        ]
      },
      "EventDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "example": "0199a1c2-7d3e-7f00-8a1b-2c3d4e5f6a7b",
            "description": "Give it to the participants' app and the live page."
          },
          "name": {
            "type": "string",
            "example": "Улаанбаатар марафон 2027"
          },
          "bbox": {
            "example": [
              106.85,
              47.88,
              106.98,
              47.93
            ],
            "description": "[west, south, east, north]",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "starts_at": {
            "type": "string",
            "example": "2027-06-12T00:00:00.000Z"
          },
          "ends_at": {
            "type": "string",
            "example": "2027-06-12T06:00:00.000Z"
          },
          "closes_at": {
            "type": "string",
            "example": "2027-06-12T06:15:00.000Z",
            "description": "When the points are erased: 15 minutes after ends_at."
          },
          "closed": {
            "type": "boolean",
            "example": false,
            "description": "true once the points are erased; the heat cells stay."
          }
        },
        "required": [
          "id",
          "name",
          "bbox",
          "starts_at",
          "ends_at",
          "closes_at",
          "closed"
        ]
      },
      "EventPositionBodyDto": {
        "type": "object",
        "properties": {
          "format": {
            "type": "string",
            "enum": [
              "dock.position.v1"
            ],
            "example": "dock.position.v1"
          },
          "consent": {
            "type": "string",
            "enum": [
              "opt_in"
            ],
            "example": "opt_in",
            "description": "Send only after the participant said yes. Anything else is 400 consent_required."
          },
          "participant": {
            "type": "string",
            "example": "h4w2k9m0c7x3v8q1z5r6",
            "minLength": 16,
            "maxLength": 64,
            "pattern": "^[A-Za-z0-9_-]{16,64}$",
            "description": "A random token the app makes when it starts sending, so dock can tell participants apart inside the event. Never a name, bib, phone or device id."
          },
          "points": {
            "type": "array",
            "minItems": 1,
            "maxItems": 900,
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 3,
              "maxItems": 3
            },
            "example": [
              [
                106.9177,
                47.9186,
                1812420000
              ],
              [
                106.9181,
                47.9187,
                1812420010
              ]
            ],
            "description": "[lon, lat, t]: WGS84 degrees and whole seconds UTC, inside Mongolia, t rising, within the last hour. Nothing else per point."
          }
        },
        "required": [
          "format",
          "consent",
          "participant",
          "points"
        ]
      },
      "EventPositionsDto": {
        "type": "object",
        "properties": {
          "points": {
            "type": "number",
            "example": 2,
            "description": "Points in the batch."
          },
          "kept": {
            "type": "number",
            "example": 2,
            "description": "Points stored until the event closes."
          },
          "outside": {
            "type": "number",
            "example": 0,
            "description": "Points left out: outside the event's area or time."
          },
          "restricted": {
            "type": "number",
            "example": 0,
            "description": "Points left out: inside a restricted site."
          }
        },
        "required": [
          "points",
          "kept",
          "outside",
          "restricted"
        ]
      },
      "EventLivePointDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "geometry": {
            "type": "object",
            "example": {
              "type": "Point",
              "coordinates": [
                106.9181,
                47.9187
              ]
            },
            "description": "a participant's last point, to 4 decimals"
          },
          "properties": {
            "type": "object",
            "example": {},
            "description": "always empty: nothing about the participant"
          }
        },
        "required": [
          "type",
          "geometry",
          "properties"
        ]
      },
      "EventLiveDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ]
          },
          "at": {
            "type": "string",
            "example": "2027-06-12T03:41:07.000Z",
            "description": "the answer's time; points are from the 2 minutes before it"
          },
          "participants": {
            "type": "number",
            "example": 212,
            "description": "participants shown; 0 when fewer than 5 are live, then features is empty"
          },
          "rule": {
            "type": "object",
            "description": "The rule the answer follows, keys as written"
          },
          "features": {
            "description": "one point per live participant, sorted by place",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventLivePointDto"
            }
          }
        },
        "required": [
          "type",
          "at",
          "participants",
          "rule",
          "features"
        ]
      },
      "EventHeatCellDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "geometry": {
            "type": "object",
            "example": {
              "type": "Polygon",
              "coordinates": [
                [
                  [
                    106.9168,
                    47.9179
                  ],
                  [
                    106.9181,
                    47.9179
                  ],
                  [
                    106.9181,
                    47.9188
                  ],
                  [
                    106.9168,
                    47.9188
                  ],
                  [
                    106.9168,
                    47.9179
                  ]
                ]
              ]
            },
            "description": "the cell, a 150-unit EPSG:3857 square, in WGS84"
          },
          "properties": {
            "type": "object",
            "example": {
              "participants": 37
            },
            "description": "participants: distinct participants with a point in the cell, 5 or more"
          }
        },
        "required": [
          "type",
          "geometry",
          "properties"
        ]
      },
      "EventHeatDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ]
          },
          "window": {
            "type": "object",
            "nullable": true,
            "example": {
              "from": "2027-06-12T03:30:00.000Z",
              "to": "2027-06-12T03:45:00.000Z"
            },
            "description": "the 15-minute window; null for the whole event"
          },
          "closed": {
            "type": "boolean",
            "example": false,
            "description": "true once the event is closed: the cells are final"
          },
          "rule": {
            "type": "object",
            "description": "The rule each cell passed; any other cell is left out"
          },
          "features": {
            "description": "cells from north to south, west to east",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventHeatCellDto"
            }
          }
        },
        "required": [
          "type",
          "window",
          "closed",
          "rule",
          "features"
        ]
      },
      "CorridorTotalsDto": {
        "type": "object",
        "properties": {
          "corridors": {
            "type": "number",
            "example": 6
          },
          "verified_track_km": {
            "type": "number",
            "example": 0,
            "description": "Track km verified by matched trips of 3 or more vehicles, all corridors."
          }
        },
        "required": [
          "corridors",
          "verified_track_km"
        ]
      },
      "CorridorCompareDto": {
        "type": "object",
        "properties": {
          "rule": {
            "type": "string",
            "example": "one row per corridor, every value copied from its facts; ranked by the share of cross-sections with 3 or more ruts ..."
          },
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "example": [
              {
                "name": "bayanzag",
                "label": "Bulgan soum to Bayanzag (Flaming Cliffs), Ömnögovi",
                "label_mn": "Булган сумаас Баянзаг хүртэл, Өмнөговь",
                "years": [
                  2016,
                  2026
                ],
                "clear_years": 9,
                "stretch_km": 16.18,
                "envelope_km2": 6.05,
                "braided_share": 0.136,
                "braided_share_shown": "14%",
                "braided_year": 2026,
                "verified_track_km": 0,
                "confidence": 0.26,
                "rank": 1
              }
            ],
            "description": "One row per corridor, ranked by braided_share, unknown last (rank null). confidence is the ranked share's; null means unknown. label_mn is the Mongolian label, null when the corridor has none. Fields are as lane D's compare rows write them; new ones may be added."
          }
        },
        "required": [
          "rule",
          "rows"
        ]
      },
      "CorridorsDto": {
        "type": "object",
        "properties": {
          "method": {
            "type": "string",
            "example": "dock_steppe.facts v3"
          },
          "made": {
            "type": "string",
            "example": "2026-10-04T17:18:09Z",
            "description": "When make facts wrote the file, UTC."
          },
          "rule": {
            "type": "string",
            "example": "copied from rendered files, never computed anew; faint years left out; confidence never above the corridor cap; null confidence means unknown"
          },
          "totals": {
            "$ref": "#/components/schemas/CorridorTotalsDto"
          },
          "compare": {
            "$ref": "#/components/schemas/CorridorCompareDto"
          },
          "attribution": {
            "example": [
              "Contains modified Copernicus Sentinel data 2016-2026",
              "Track centerline and rivers: (c) OpenStreetMap contributors, ODbL"
            ],
            "description": "Show these lines wherever the numbers are shown.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "method",
          "made",
          "rule",
          "totals",
          "compare",
          "attribution"
        ]
      },
      "CorridorFactDto": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "example": "braided_share"
          },
          "value": {
            "type": "object",
            "example": 0.136,
            "description": "A number, an object of numbers, or null for unknown."
          },
          "unit": {
            "type": "string",
            "example": "share",
            "nullable": true
          },
          "text": {
            "type": "string",
            "example": "14% of cross-sections carry 3 or more ruts in 2026."
          },
          "text_mn": {
            "type": "string",
            "example": "2026 онд хөндлөн огтлолын 14% нь 3 ба түүнээс олон мөртэй.",
            "nullable": true,
            "description": "The same line in Mongolian, with the same numbers. Null when no Mongolian line states them: unknown, not a translation."
          },
          "confidence": {
            "type": "number",
            "example": 0.26,
            "nullable": true,
            "description": "0 to 1, never above confidence_cap; null means unknown."
          },
          "source": {
            "type": "string",
            "example": "dashboard/bayanzag/data/data.json cross.share_3plus"
          },
          "caveat": {
            "type": "string",
            "example": "Sentinel-2 detection, 10 m pixels, not field checked",
            "nullable": true
          }
        },
        "required": [
          "key",
          "value",
          "unit",
          "text",
          "text_mn",
          "confidence",
          "source",
          "caveat"
        ]
      },
      "CorridorDto": {
        "type": "object",
        "properties": {
          "method": {
            "type": "string",
            "example": "dock_steppe.facts v3"
          },
          "made": {
            "type": "string",
            "example": "2026-10-04T17:18:09Z",
            "description": "When make facts wrote the file, UTC."
          },
          "rule": {
            "type": "string",
            "example": "copied from rendered files, never computed anew; faint years left out; confidence never above the corridor cap; null confidence means unknown"
          },
          "name": {
            "type": "string",
            "example": "bayanzag"
          },
          "label": {
            "type": "string",
            "example": "Bulgan soum to Bayanzag (Flaming Cliffs), Ömnögovi"
          },
          "label_mn": {
            "type": "string",
            "example": "Булган сумаас Баянзаг хүртэл, Өмнөговь",
            "nullable": true,
            "description": "Null when the corridor has no Mongolian label."
          },
          "corridor_method": {
            "type": "string",
            "example": "dock_steppe.detect v16",
            "description": "The detection the numbers come from."
          },
          "confidence_cap": {
            "type": "number",
            "example": 0.3,
            "nullable": true,
            "description": "No fact line of this corridor is surer than this."
          },
          "confidence_note": {
            "type": "string",
            "example": "blind model labels on 2023: precision 0.48, est. recall 0.31",
            "nullable": true
          },
          "confidence_note_mn": {
            "type": "string",
            "example": "2023 оны сохор загварын шошго: нарийвчлал 0.48, бүрэн байдлын үнэлгээ 0.31",
            "nullable": true,
            "description": "confidence_note in Mongolian, null when there is none."
          },
          "attribution": {
            "example": [
              "Contains modified Copernicus Sentinel data 2016-2026"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "facts": {
            "description": "Every fact line with its text, confidence, source and caveat. Lines carry more fields per key (years, halfwidth_m, ...), served as written.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CorridorFactDto"
            }
          }
        },
        "required": [
          "method",
          "made",
          "rule",
          "name",
          "label",
          "label_mn",
          "corridor_method",
          "confidence_cap",
          "confidence_note",
          "confidence_note_mn",
          "attribution",
          "facts"
        ]
      },
      "NotesBodyDto": {
        "type": "object",
        "properties": {
          "instructions_mn": {
            "type": "string",
            "nullable": true,
            "maxLength": 500,
            "example": "Зүүн талын хаалга дээр «Сансар» гэсэн самбар.",
            "description": "For guests who read Mongolian. 1 to 500 characters, spaces collapsed. No phone number, no e-mail. null or absent: none in this language."
          },
          "instructions_en": {
            "type": "string",
            "nullable": true,
            "maxLength": 500,
            "example": "Second entrance on the east side, sign «Сансар» above the door.",
            "description": "For guests who read English. 1 to 500 characters, spaces collapsed. No phone number, no e-mail. null or absent: none in this language."
          }
        }
      },
      "NoteReceiptDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "01928f3e-7a1b-7c2d-8e4f-0123456789ab",
            "description": "The waiting note; writing again keeps it."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "updated",
              "unchanged"
            ],
            "description": "queued: a new note waits for review. updated: your waiting note now has this text. unchanged: it had."
          },
          "name": {
            "type": "string",
            "example": "Сансар бэйкери"
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "description": "The door the name points at, which the note is for."
          },
          "instructions_mn": {
            "type": "string",
            "nullable": true,
            "example": "Зүүн талын хаалга дээр «Сансар» гэсэн самбар."
          },
          "instructions_en": {
            "type": "string",
            "nullable": true,
            "example": "Second entrance on the east side, sign «Сансар» above the door."
          },
          "received_at": {
            "type": "string",
            "example": "2026-10-05T06:12:40Z",
            "description": "When the waiting text was last written."
          },
          "next": {
            "type": "string",
            "enum": [
              "review"
            ],
            "description": "A person reviews the note. Until then GET /v1/door/{code} serves the notes the map holds, not this one."
          }
        },
        "required": [
          "id",
          "status",
          "name",
          "code",
          "instructions_mn",
          "instructions_en",
          "received_at",
          "next"
        ]
      },
      "NoteStateDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "01928f3e-7a1b-7c2d-8e4f-0123456789ab"
          },
          "state": {
            "type": "string",
            "enum": [
              "waiting",
              "accepted",
              "refused"
            ],
            "description": "waiting: a person has not reviewed it; guests do not see it. accepted: GET /v1/door/{code} serves the languages it gave, until a later change to the door. refused: not used; the door kept its notes."
          },
          "instructions_mn": {
            "type": "string",
            "nullable": true,
            "example": "Зүүн талын хаалга дээр «Сансар» гэсэн самбар."
          },
          "instructions_en": {
            "type": "string",
            "nullable": true,
            "example": "Second entrance on the east side, sign «Сансар» above the door."
          },
          "received_at": {
            "type": "string",
            "example": "2026-10-05T06:12:40Z",
            "description": "When this text was last written."
          },
          "reviewed_at": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "When a person accepted or refused it; null while it waits."
          }
        },
        "required": [
          "id",
          "state",
          "instructions_mn",
          "instructions_en",
          "received_at",
          "reviewed_at"
        ]
      },
      "NoteListDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Сансар бэйкери"
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "description": "The door the name points at now; its notes are listed."
          },
          "notes": {
            "description": "Your org's notes for this door, under any of its names: the waiting one first, then the newest review first, at most 20. Other orgs' notes are never listed. Empty: you wrote none.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NoteStateDto"
            }
          }
        },
        "required": [
          "name",
          "code",
          "notes"
        ]
      },
      "PhotoReceiptDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "01928f3e-7b2c-7d3e-8f4a-0123456789ab",
            "description": "The waiting photo; sending again keeps it."
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "updated",
              "unchanged"
            ],
            "description": "queued: a new photo waits for review. updated: your waiting photo is now this one. unchanged: it was."
          },
          "name": {
            "type": "string",
            "example": "Сансар бэйкери"
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "description": "The door the name points at, which the photo is for."
          },
          "sha256": {
            "type": "string",
            "example": "d5e52da641c5a3f0b8e1c7d2a4f6e8b0c1d3e5f7a9b2c4d6e8f0a1b3c5d7e9f1",
            "description": "SHA-256 of the photo as stored, after its metadata was removed: not the hash of the file you sent."
          },
          "bytes": {
            "type": "integer",
            "example": 7332,
            "description": "Size as stored, in bytes."
          },
          "width": {
            "type": "integer",
            "example": 480,
            "description": "Pixels as stored, before the EXIF orientation turns it."
          },
          "height": {
            "type": "integer",
            "example": 360
          },
          "received_at": {
            "type": "string",
            "example": "2026-10-05T06:12:40Z",
            "description": "When the waiting photo was last sent."
          },
          "next": {
            "type": "string",
            "enum": [
              "review"
            ],
            "description": "A person reviews the photo. Once accepted, GET /v1/door-names/{name}/photo serves it."
          }
        },
        "required": [
          "id",
          "status",
          "name",
          "code",
          "sha256",
          "bytes",
          "width",
          "height",
          "received_at",
          "next"
        ]
      },
      "AuditSampleDto": {
        "type": "object",
        "properties": {
          "tag": {
            "type": "string",
            "example": "2026-10"
          },
          "created_at": {
            "type": "string",
            "example": "2026-10-01T16:40:00.000Z"
          },
          "seed": {
            "type": "string",
            "example": "202610",
            "description": "Draw seed, so anyone can redraw and compare."
          },
          "n": {
            "type": "number",
            "example": 300
          },
          "scope": {
            "type": "string",
            "example": "pilot_bbox"
          },
          "population": {
            "type": "number",
            "example": 4798,
            "description": "Current entrances in scope the sample was drawn from."
          },
          "drawn": {
            "type": "number",
            "example": 300,
            "description": "Items in the sample."
          },
          "checked": {
            "type": "number",
            "example": 0,
            "description": "Items with an answer."
          }
        },
        "required": [
          "tag",
          "created_at",
          "seed",
          "n",
          "scope",
          "population",
          "drawn",
          "checked"
        ]
      },
      "AuditSampleListDto": {
        "type": "object",
        "properties": {
          "samples": {
            "description": "Newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditSampleDto"
            }
          }
        },
        "required": [
          "samples"
        ]
      },
      "AuditProgressDto": {
        "type": "object",
        "properties": {
          "found": {
            "type": "number"
          },
          "wrong_location": {
            "type": "number"
          },
          "missing": {
            "type": "number"
          },
          "no_access": {
            "type": "number"
          },
          "unchecked": {
            "type": "number",
            "description": "Not visited yet."
          }
        },
        "required": [
          "found",
          "wrong_location",
          "missing",
          "no_access",
          "unchecked"
        ]
      },
      "AuditItemDto": {
        "type": "object",
        "properties": {
          "seq": {
            "type": "integer",
            "example": 1,
            "description": "Walk order: district, then street by street."
          },
          "entrance": {
            "type": "string",
            "format": "uuid",
            "description": "The entrance drawn. An id, never an address."
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "nullable": true
          },
          "label_mn": {
            "type": "string",
            "example": "Сансар А 8",
            "nullable": true
          },
          "label_en": {
            "type": "string",
            "example": "Sansar A 8",
            "nullable": true
          },
          "official": {
            "type": "boolean",
            "description": "false: no state address matched. Show it as unofficial."
          },
          "district_mn": {
            "type": "string",
            "example": "Хан-Уул",
            "nullable": true
          },
          "kind": {
            "type": "string",
            "enum": [
              "door",
              "gate",
              "vehicle_gate",
              "stairwell"
            ]
          },
          "source": {
            "type": "string",
            "example": "generated"
          },
          "confidence": {
            "type": "number",
            "example": 0,
            "nullable": true
          },
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "description": "[lon, lat] the map has for this entrance.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "result": {
            "type": "string",
            "enum": [
              "found",
              "wrong_location",
              "missing",
              "no_access"
            ],
            "nullable": true,
            "description": "null: not visited."
          },
          "method": {
            "type": "string",
            "enum": [
              "rtk",
              "imagery_tap",
              "tape"
            ],
            "nullable": true
          },
          "checked": {
            "nullable": true,
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "checked_at": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-05T03:20:00.000Z"
          },
          "distance_m": {
            "type": "number",
            "nullable": true,
            "example": 1.4,
            "description": "Metres from point to checked."
          }
        },
        "required": [
          "seq",
          "entrance",
          "code",
          "label_mn",
          "label_en",
          "official",
          "district_mn",
          "kind",
          "source",
          "confidence",
          "point",
          "result",
          "method",
          "checked",
          "checked_at",
          "distance_m"
        ]
      },
      "AuditChecklistDto": {
        "type": "object",
        "properties": {
          "tag": {
            "type": "string",
            "example": "2026-10"
          },
          "created_at": {
            "type": "string",
            "example": "2026-10-01T16:40:00.000Z"
          },
          "seed": {
            "type": "string",
            "example": "202610",
            "description": "Draw seed, so anyone can redraw and compare."
          },
          "n": {
            "type": "number",
            "example": 300
          },
          "scope": {
            "type": "string",
            "example": "pilot_bbox"
          },
          "population": {
            "type": "number",
            "example": 4798,
            "description": "Current entrances in scope the sample was drawn from."
          },
          "drawn": {
            "type": "number",
            "example": 300,
            "description": "Items in the sample."
          },
          "checked": {
            "type": "number",
            "example": 0,
            "description": "Items with an answer."
          },
          "progress": {
            "$ref": "#/components/schemas/AuditProgressDto"
          },
          "hidden": {
            "type": "number",
            "example": 0,
            "description": "Items now inside a restricted site: not shown, not written."
          },
          "items": {
            "description": "In seq order.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditItemDto"
            }
          }
        },
        "required": [
          "tag",
          "created_at",
          "seed",
          "n",
          "scope",
          "population",
          "drawn",
          "checked",
          "progress",
          "hidden",
          "items"
        ]
      },
      "AuditCheckBodyDto": {
        "type": "object",
        "properties": {
          "result": {
            "type": "string",
            "enum": [
              "found",
              "wrong_location",
              "missing",
              "no_access"
            ],
            "nullable": true,
            "description": "found: the door is there (needs checked and method). wrong_location: the door is real but elsewhere (checked and method if measured; without them it counts as outside 5 m). missing: no door. no_access: could not reach it (left out of the share). null clears a wrong answer and takes no other field."
          },
          "checked": {
            "example": [
              106.930113,
              47.920104
            ],
            "description": "[lon, lat] WGS84 of the door as measured.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "method": {
            "type": "string",
            "enum": [
              "rtk",
              "imagery_tap",
              "tape"
            ],
            "description": "How checked was measured: an RTK fix, a tap on imagery at the door, or a tape from a mapped corner."
          },
          "device": {
            "example": [
              106.93013,
              47.92012
            ],
            "description": "Phone or rover [lon, lat] when sent. A check only: within 40 m of checked (no checked: of the drawn point; no_access: 150 m). Required unless result is null.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "checked_at": {
            "type": "string",
            "example": "2026-10-05T11:20:00+08:00",
            "description": "When the surveyor was there, if the app queued the answer offline. ISO 8601 with a zone, at most 7 days ago."
          }
        },
        "required": [
          "result",
          "device"
        ]
      },
      "AuditCheckDto": {
        "type": "object",
        "properties": {
          "seq": {
            "type": "integer",
            "example": 1,
            "description": "Walk order: district, then street by street."
          },
          "entrance": {
            "type": "string",
            "format": "uuid",
            "description": "The entrance drawn. An id, never an address."
          },
          "code": {
            "type": "string",
            "example": "7QSVX",
            "nullable": true
          },
          "label_mn": {
            "type": "string",
            "example": "Сансар А 8",
            "nullable": true
          },
          "label_en": {
            "type": "string",
            "example": "Sansar A 8",
            "nullable": true
          },
          "official": {
            "type": "boolean",
            "description": "false: no state address matched. Show it as unofficial."
          },
          "district_mn": {
            "type": "string",
            "example": "Хан-Уул",
            "nullable": true
          },
          "kind": {
            "type": "string",
            "enum": [
              "door",
              "gate",
              "vehicle_gate",
              "stairwell"
            ]
          },
          "source": {
            "type": "string",
            "example": "generated"
          },
          "confidence": {
            "type": "number",
            "example": 0,
            "nullable": true
          },
          "point": {
            "example": [
              106.9376,
              47.9226
            ],
            "description": "[lon, lat] the map has for this entrance.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "result": {
            "type": "string",
            "enum": [
              "found",
              "wrong_location",
              "missing",
              "no_access"
            ],
            "nullable": true,
            "description": "null: not visited."
          },
          "method": {
            "type": "string",
            "enum": [
              "rtk",
              "imagery_tap",
              "tape"
            ],
            "nullable": true
          },
          "checked": {
            "nullable": true,
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "checked_at": {
            "type": "string",
            "nullable": true,
            "example": "2026-10-05T03:20:00.000Z"
          },
          "distance_m": {
            "type": "number",
            "nullable": true,
            "example": 1.4,
            "description": "Metres from point to checked."
          },
          "gps_m": {
            "type": "number",
            "nullable": true,
            "example": 3.2,
            "description": "Metres from the device to checked (or to point). null when cleared."
          }
        },
        "required": [
          "seq",
          "entrance",
          "code",
          "label_mn",
          "label_en",
          "official",
          "district_mn",
          "kind",
          "source",
          "confidence",
          "point",
          "result",
          "method",
          "checked",
          "checked_at",
          "distance_m",
          "gps_m"
        ]
      },
      "NearVenueDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name_mn": {
            "type": "string"
          },
          "category": {
            "type": "string",
            "example": "transport"
          },
          "distance_m": {
            "type": "number",
            "example": 0,
            "description": "Metres from the point to the outline; 0 when the point is inside."
          },
          "levels": {
            "description": "Current floor numbers, lowest first.",
            "type": "array",
            "items": {
              "type": "number"
            }
          }
        },
        "required": [
          "id",
          "name_mn",
          "category",
          "distance_m",
          "levels"
        ]
      },
      "NearVenuesDto": {
        "type": "object",
        "properties": {
          "results": {
            "description": "Nearest first, at most 10; empty when no venue is within 200 m.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NearVenueDto"
            }
          }
        },
        "required": [
          "results"
        ]
      },
      "IndoorLevelDto": {
        "type": "object",
        "properties": {
          "ordinal": {
            "type": "number",
            "example": 1,
            "description": "The floor number as people say it: 0 ground, 1 first, -1 basement."
          },
          "short_name_mn": {
            "type": "string",
            "example": "1"
          },
          "name_mn": {
            "type": "string",
            "nullable": true,
            "example": "1 давхар"
          },
          "outdoor": {
            "type": "boolean"
          },
          "source": {
            "type": "string",
            "example": "dock:survey"
          },
          "confidence": {
            "type": "number",
            "nullable": true,
            "description": "0 to 1. null is unknown."
          }
        },
        "required": [
          "ordinal",
          "short_name_mn",
          "name_mn",
          "outdoor",
          "source",
          "confidence"
        ]
      },
      "VenueDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name_mn": {
            "type": "string"
          },
          "name_en": {
            "type": "string",
            "nullable": true
          },
          "category": {
            "type": "string",
            "example": "transport"
          },
          "source": {
            "type": "string"
          },
          "confidence": {
            "type": "number",
            "nullable": true
          },
          "building_code": {
            "type": "string",
            "nullable": true,
            "example": "R0RP0",
            "description": "Building code of the building the venue stands in; null when it has none yet."
          },
          "admin": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "example": {
              "district_mn": "Сэргэлэн",
              "district_en": "Sergelen",
              "khoroo": null,
              "soum_mn": "Сэргэлэн",
              "aimag_mn": "Төв"
            },
            "description": "District and khoroo covering the venue, and the soum and aimag (OSM boundaries, API 0.103.0); null when no polygon covers it."
          },
          "outline": {
            "type": "object",
            "additionalProperties": true,
            "description": "GeoJSON Polygon, [lon, lat]."
          },
          "levels": {
            "description": "Current floors, lowest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IndoorLevelDto"
            }
          }
        },
        "required": [
          "id",
          "name_mn",
          "name_en",
          "category",
          "source",
          "confidence",
          "building_code",
          "admin",
          "outline",
          "levels"
        ]
      },
      "LevelFeatureDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "id": {
            "type": "string"
          },
          "geometry": {
            "type": "object",
            "additionalProperties": true
          },
          "properties": {
            "type": "object",
            "additionalProperties": true,
            "description": "feature_type is unit, opening or amenity; then category, category_mn (plain Mongolian word, null when unknown), level, source, confidence, and the names, number and area a unit has."
          }
        },
        "required": [
          "type",
          "id",
          "geometry",
          "properties"
        ]
      },
      "LevelDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ]
          },
          "venue_id": {
            "type": "string"
          },
          "level": {
            "type": "number"
          },
          "features": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LevelFeatureDto"
            }
          }
        },
        "required": [
          "type",
          "venue_id",
          "level",
          "features"
        ]
      },
      "WalkNetDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "FeatureCollection"
            ]
          },
          "venue_id": {
            "type": "string"
          },
          "level": {
            "type": "number"
          },
          "features": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Corridor LineStrings of this floor, [lon, lat]. feature_type walkway."
          },
          "connectors": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Points on this floor where stairs, an escalator or a lift lead to another floor: category, to_level, direction (both or up), name_mn."
          }
        },
        "required": [
          "type",
          "venue_id",
          "level",
          "features",
          "connectors"
        ]
      },
      "IndoorSpotDto": {
        "type": "object",
        "properties": {
          "venue_id": {
            "type": "string"
          },
          "venue_name_mn": {
            "type": "string"
          },
          "unit_id": {
            "type": "string"
          },
          "level": {
            "type": "number"
          },
          "level_name_mn": {
            "type": "string",
            "example": "2 давхар"
          },
          "name_mn": {
            "type": "string",
            "nullable": true
          },
          "number": {
            "type": "string",
            "nullable": true
          },
          "label": {
            "type": "string",
            "example": "Бизнэс танхим"
          },
          "point": {
            "description": "[lon, lat]: the unit anchor, else a point inside it.",
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "link": {
            "type": "string",
            "example": "https://map.dock.mn/indoor/?venue=0198a2b4-1c3d-7e5f-8a9b-0c1d2e3f4a5b#0198a2b4-1c3d-7e5f-8a9b-0c1d2e3f4a5c",
            "description": "What the plate QR holds."
          },
          "source": {
            "type": "string"
          },
          "confidence": {
            "type": "number",
            "nullable": true
          }
        },
        "required": [
          "venue_id",
          "venue_name_mn",
          "unit_id",
          "level",
          "level_name_mn",
          "name_mn",
          "number",
          "label",
          "point",
          "link",
          "source",
          "confidence"
        ]
      },
      "IndoorLegDto": {
        "type": "object",
        "properties": {
          "floor": {
            "type": "number",
            "example": 0
          },
          "distance_m": {
            "type": "number"
          },
          "geometry": {
            "type": "object",
            "additionalProperties": true,
            "description": "GeoJSON LineString on this floor, [lon, lat]."
          },
          "ends_with": {
            "type": "string",
            "enum": [
              "stairs",
              "escalator",
              "elevator",
              "arrive"
            ],
            "description": "How the leg ends."
          },
          "to_floor": {
            "type": "number",
            "nullable": true,
            "description": "The floor a connector reaches; null on arrival."
          }
        },
        "required": [
          "floor",
          "distance_m",
          "geometry",
          "ends_with",
          "to_floor"
        ]
      },
      "IndoorStepDto": {
        "type": "object",
        "properties": {
          "floor": {
            "type": "number",
            "example": 0
          },
          "text": {
            "type": "string",
            "example": "Зүүн тийш 40 м алхана."
          },
          "distance_m": {
            "type": "number"
          },
          "at": {
            "example": [
              106.7632,
              47.8431
            ],
            "description": "[lon, lat] where the step begins.",
            "type": "array",
            "items": {
              "type": "number"
            }
          }
        },
        "required": [
          "floor",
          "text",
          "distance_m",
          "at"
        ]
      },
      "IndoorRouteDto": {
        "type": "object",
        "properties": {
          "venue_id": {
            "type": "string"
          },
          "distance_m": {
            "type": "number"
          },
          "duration_s": {
            "type": "number"
          },
          "legs": {
            "description": "One per floor walked, in order.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IndoorLegDto"
            }
          },
          "steps": {
            "description": "Mongolian directions, the floor on each.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IndoorStepDto"
            }
          },
          "to": {
            "type": "object",
            "additionalProperties": true,
            "description": "The unit: level, point, name_mn, number, source, confidence, door_hours (hours of a drawn door within 2 m of the unit, or null)."
          }
        },
        "required": [
          "venue_id",
          "distance_m",
          "duration_s",
          "legs",
          "steps",
          "to"
        ]
      },
      "IndoorRoadDto": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "driving",
              "walking",
              "cycling"
            ]
          },
          "distance_m": {
            "type": "number"
          },
          "duration_s": {
            "type": "number"
          },
          "geometry": {
            "type": "object",
            "additionalProperties": true,
            "description": "GeoJSON LineString, [lon, lat]: the road to the entrance."
          },
          "steps": {
            "description": "The road steps in Mongolian (mn) and English (en), as GET /v1/route gives them.",
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "entrance": {
            "type": "object",
            "additionalProperties": true,
            "description": "The entrance used: level, point, core_entrance_id (null when drawn only inside)."
          }
        },
        "required": [
          "mode",
          "distance_m",
          "duration_s",
          "geometry",
          "steps",
          "entrance"
        ]
      },
      "IndoorDirectionsDto": {
        "type": "object",
        "properties": {
          "venue_id": {
            "type": "string"
          },
          "distance_m": {
            "type": "number",
            "description": "Road plus walk."
          },
          "duration_s": {
            "type": "number",
            "description": "Road plus walk."
          },
          "road": {
            "$ref": "#/components/schemas/IndoorRoadDto"
          },
          "indoor": {
            "description": "The walk inside, from the entrance, as GET /v1/venue/{id}/route.",
            "allOf": [
              {
                "$ref": "#/components/schemas/IndoorRouteDto"
              }
            ]
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Notes that do not block the walk. code entrance_closed: the entrance used has opening hours and is closed at the time of arrival (hours, message, message_mn). No hours on the door means no warning. code destination_closed: the unit's own door has hours and is closed on arrival."
          }
        },
        "required": [
          "venue_id",
          "distance_m",
          "duration_s",
          "road",
          "indoor",
          "warnings"
        ]
      },
      "PushDeviceBodyDto": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "example": "fcm-or-apns-token-0123456789abcdef",
            "description": "The push token of the phone, 16 to 512 characters."
          },
          "platform": {
            "type": "string",
            "enum": [
              "ios",
              "android"
            ],
            "example": "ios"
          },
          "codes": {
            "example": [
              "R0RP0"
            ],
            "description": "Building codes this phone follows, up to 50. Replaces the earlier list.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "token",
          "platform"
        ]
      },
      "PushDeviceDto": {
        "type": "object",
        "properties": {
          "codes": {
            "example": [
              "R0RP0"
            ],
            "description": "The codes now followed.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "codes"
        ]
      },
      "PushForgetBodyDto": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "example": "fcm-or-apns-token-0123456789abcdef"
          }
        },
        "required": [
          "token"
        ]
      }
    }
  }
}
