openapi: 3.0.3
info:
  title: LatLng API
  version: "1.0.0"
  description: |
    LatLng provides affordable maps and location APIs for developers building location-aware apps.

    The API includes forward geocoding, reverse geocoding, places search, nearby places,
    place categories, static maps, and custom dataset map tiles powered by OpenStreetMap data.

    Developers can start free with a generous daily quota. LatLng also offers an MCP server
    so AI tools can use location APIs directly.

    Homepage: https://www.latlng.work
    Documentation: https://www.latlng.work/docs
    Get a free API key: https://dash.latlng.work
    MCP server: https://mcp.latlng.work/mcp
  termsOfService: https://www.latlng.work/terms
  contact:
    name: LatLng
    url: https://www.latlng.work
    email: support@latlng.work
servers:
  - url: https://api.latlng.work
    description: Production API
externalDocs:
  description: LatLng documentation
  url: https://www.latlng.work/docs
tags:
  - name: Geocoding
    description: Convert addresses and place names to coordinates, and coordinates to addresses.
  - name: Places
    description: Search and discover OpenStreetMap points of interest.
  - name: Maps
    description: Generate static maps.
  - name: Datasets
    description: Upload and manage custom geospatial datasets.
  - name: Utility
    description: Health and utility endpoints.
security:
  - ApiKeyAuth: []
  - ApiKeyQuery: []
paths:
  /api:
    get:
      tags: [Geocoding]
      summary: Forward geocoding
      description: Convert an address or place name to GeoJSON coordinates.
      operationId: forwardGeocode
      parameters:
        - $ref: "#/components/parameters/ApiKeyQuery"
        - name: q
          in: query
          required: true
          schema:
            type: string
          example: Berlin
          description: Address or place name to geocode.
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 50
          example: 5
        - name: lang
          in: query
          schema:
            type: string
          example: en
        - name: lat
          in: query
          schema:
            type: number
            format: double
          example: 52.52
          description: Bias results near this latitude.
        - name: lon
          in: query
          schema:
            type: number
            format: double
          example: 13.405
          description: Bias results near this longitude.
      responses:
        "200":
          description: GeoJSON feature collection.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GeoJsonFeatureCollection"
              example:
                type: FeatureCollection
                features:
                  - type: Feature
                    geometry:
                      type: Point
                      coordinates: [13.3888599, 52.5170365]
                    properties:
                      name: Berlin
                      country: Germany
                      state: Berlin
                      osm_key: place
                      osm_value: city
        "400":
          $ref: "#/components/responses/BadRequest"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/Unavailable"
  /reverse:
    get:
      tags: [Geocoding]
      summary: Reverse geocoding
      description: Convert latitude and longitude to nearby address/place results.
      operationId: reverseGeocode
      parameters:
        - $ref: "#/components/parameters/ApiKeyQuery"
        - name: lat
          in: query
          required: true
          schema:
            type: number
            format: double
          example: 52.517
        - name: lon
          in: query
          required: true
          schema:
            type: number
            format: double
          example: 13.389
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 50
          example: 5
        - name: lang
          in: query
          schema:
            type: string
          example: en
      responses:
        "200":
          description: GeoJSON feature collection.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GeoJsonFeatureCollection"
        "400":
          $ref: "#/components/responses/BadRequest"
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          $ref: "#/components/responses/Unavailable"
  /v1/places/nearby:
    get:
      tags: [Places]
      summary: Nearby places
      description: Find OpenStreetMap points of interest near a coordinate.
      operationId: placesNearby
      parameters:
        - $ref: "#/components/parameters/ApiKeyQuery"
        - name: lat
          in: query
          required: true
          schema:
            type: number
            format: double
          example: 40.748
        - name: lon
          in: query
          required: true
          schema:
            type: number
            format: double
          example: -73.985
        - name: radius
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 50000
            default: 1000
          example: 500
          description: Search radius in meters.
        - name: type
          in: query
          schema:
            type: string
          example: cafe
          description: Optional category filter. Alias of category.
        - name: category
          in: query
          schema:
            type: string
          example: cafe
          description: Optional category filter.
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 20
          example: 10
      responses:
        "200":
          description: Nearby places response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlacesResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "429":
          $ref: "#/components/responses/RateLimited"
  /v1/places/search:
    get:
      tags: [Places]
      summary: Search places
      description: Search for places by name with optional location and category filters.
      operationId: placesSearch
      parameters:
        - $ref: "#/components/parameters/ApiKeyQuery"
        - name: q
          in: query
          required: true
          schema:
            type: string
          example: Starbucks
        - name: lat
          in: query
          schema:
            type: number
            format: double
          example: 40.748
        - name: lon
          in: query
          schema:
            type: number
            format: double
          example: -73.985
        - name: type
          in: query
          schema:
            type: string
          example: cafe
        - name: category
          in: query
          schema:
            type: string
          example: cafe
        - name: country
          in: query
          schema:
            type: string
          example: US
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 20
          example: 5
      responses:
        "200":
          description: Search places response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlacesResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "429":
          $ref: "#/components/responses/RateLimited"
  /v1/places/categories:
    get:
      tags: [Places]
      summary: Place categories
      description: List supported category filters.
      operationId: placesCategories
      security: []
      responses:
        "200":
          description: Available place categories.
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                  categories:
                    type: array
                    items:
                      type: object
                      properties:
                        category:
                          type: string
                        count:
                          type: integer
  /v1/static:
    get:
      tags: [Maps]
      summary: Static map
      description: Generate a static map image. API key can be sent as key or X-Api-Key.
      operationId: getStaticMap
      parameters:
        - name: key
          in: query
          schema:
            type: string
          example: latlng_xxxxx
        - name: center
          in: query
          schema:
            type: string
          example: "40.748,-73.985"
          description: Map center as latitude,longitude.
        - name: zoom
          in: query
          schema:
            type: integer
            minimum: 0
            maximum: 22
          example: 12
        - name: width
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 2048
          example: 800
        - name: height
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 2048
          example: 600
        - name: markers
          in: query
          schema:
            type: string
          example: "40.748,-73.985"
          description: Optional marker coordinates.
      responses:
        "200":
          description: Static map image.
          content:
            image/png:
              schema:
                type: string
                format: binary
        "400":
          $ref: "#/components/responses/BadRequest"
        "429":
          $ref: "#/components/responses/RateLimited"
    post:
      tags: [Maps]
      summary: Static map with GeoJSON
      description: Generate a static map image using a GeoJSON body overlay.
      operationId: postStaticMap
      parameters:
        - name: key
          in: query
          schema:
            type: string
          example: latlng_xxxxx
      requestBody:
        required: false
        content:
          application/geo+json:
            schema:
              $ref: "#/components/schemas/GeoJsonFeatureCollection"
          application/json:
            schema:
              $ref: "#/components/schemas/GeoJsonFeatureCollection"
      responses:
        "200":
          description: Static map image.
          content:
            image/png:
              schema:
                type: string
                format: binary
        "400":
          $ref: "#/components/responses/BadRequest"
        "429":
          $ref: "#/components/responses/RateLimited"
  /v1/datasets:
    get:
      tags: [Datasets]
      summary: List datasets
      description: List uploaded custom datasets for the authenticated key.
      operationId: listDatasets
      responses:
        "200":
          description: Dataset list.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        "401":
          $ref: "#/components/responses/Unauthorized"
    post:
      tags: [Datasets]
      summary: Upload dataset
      description: Upload a custom geospatial dataset for tile generation.
      operationId: uploadDataset
      requestBody:
        required: true
        content:
          application/octet-stream:
            schema:
              type: string
              format: binary
          application/geo+json:
            schema:
              $ref: "#/components/schemas/GeoJsonFeatureCollection"
      responses:
        "200":
          description: Dataset upload accepted.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        "401":
          $ref: "#/components/responses/Unauthorized"
  /v1/datasets/{datasetId}:
    get:
      tags: [Datasets]
      summary: Get dataset
      operationId: getDataset
      parameters:
        - name: datasetId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Dataset details.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      tags: [Datasets]
      summary: Delete dataset
      operationId: deleteDataset
      parameters:
        - name: datasetId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Dataset deleted.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /health:
    get:
      tags: [Utility]
      summary: Health check
      operationId: healthCheck
      security: []
      responses:
        "200":
          description: API is healthy.
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
    ApiKeyQuery:
      type: apiKey
      in: query
      name: api_key
  parameters:
    ApiKeyQuery:
      name: api_key
      in: query
      required: false
      schema:
        type: string
      description: API key alternative to the X-Api-Key header.
  responses:
    BadRequest:
      description: Bad request or invalid parameters.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Unauthorized:
      description: Missing or invalid API key.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    NotFound:
      description: Resource not found.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    RateLimited:
      description: Rate limit exceeded.
      headers:
        X-RateLimit-Limit:
          schema:
            type: integer
        X-RateLimit-Remaining:
          schema:
            type: integer
        X-Request-Id:
          schema:
            type: string
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Unavailable:
      description: Upstream geocoding service unavailable.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
  schemas:
    Error:
      type: object
      properties:
        error:
          type: string
        message:
          type: string
    GeoJsonFeatureCollection:
      type: object
      required: [type, features]
      properties:
        type:
          type: string
          enum: [FeatureCollection]
        features:
          type: array
          items:
            $ref: "#/components/schemas/GeoJsonFeature"
    GeoJsonFeature:
      type: object
      required: [type, geometry, properties]
      properties:
        type:
          type: string
          enum: [Feature]
        geometry:
          type: object
          required: [type, coordinates]
          properties:
            type:
              type: string
              example: Point
            coordinates:
              type: array
              items:
                type: number
        properties:
          type: object
          additionalProperties: true
    PlacesResponse:
      type: object
      properties:
        type:
          type: string
          example: nearby
        source:
          type: string
          example: latlng_places
        query:
          type: string
        center:
          type: object
          properties:
            lat:
              type: number
            lon:
              type: number
        radius_m:
          type: integer
        count:
          type: integer
        places:
          type: array
          items:
            $ref: "#/components/schemas/Place"
    Place:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        category:
          type: string
        lat:
          type: number
        lon:
          type: number
        confidence:
          type: number
        country:
          type: string
        region:
          type: string
        locality:
          type: string
        brand:
          type: string
        distance_m:
          type: number
