---
openapi: 3.0.1
info:
  title: API V1
  version: v1
paths:
  "/api/v1/areas":
    post:
      summary: Creates an area
      tags:
      - Areas
      parameters:
      - name: api_key
        in: query
        required: true
        description: API Key
        schema:
          type: string
      responses:
        '201':
          description: area created
        '422':
          description: invalid request
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: Home
                  description: The name of the area
                latitude:
                  type: number
                  example: 40.7128
                  description: The latitude of the area
                longitude:
                  type: number
                  example: -74.006
                  description: The longitude of the area
                radius:
                  type: number
                  example: 100
                  description: The radius of the area in meters
              required:
              - name
              - latitude
              - longitude
              - radius
            examples:
              '0':
                summary: Creates an area
                value:
                  name: Home
                  latitude: 40.7128
                  longitude: -74.006
                  radius: 100
    get:
      summary: Retrieves all areas
      tags:
      - Areas
      parameters:
      - name: api_key
        in: query
        required: true
        description: API Key
        schema:
          type: string
      responses:
        '200':
          description: areas found
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: integer
                      example: 1
                      description: The ID of the area
                    name:
                      type: string
                      example: Home
                      description: The name of the area
                    latitude:
                      type: number
                      example: 40.7128
                      description: The latitude of the area
                    longitude:
                      type: number
                      example: -74.006
                      description: The longitude of the area
                    radius:
                      type: number
                      example: 100
                      description: The radius of the area in meters
                  required:
                  - id
                  - name
                  - latitude
                  - longitude
                  - radius
  "/api/v1/areas/{id}":
    delete:
      summary: Deletes an area
      tags:
      - Areas
      parameters:
      - name: api_key
        in: query
        required: true
        description: API Key
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Area ID
        schema:
          type: string
      responses:
        '200':
          description: area deleted
  "/api/v1/countries/visited_cities":
    get:
      summary: Get visited cities by date range
      tags:
      - Countries
      description: Returns a list of visited cities and countries based on tracked
        points within the specified date range
      parameters:
      - name: api_key
        in: query
        required: true
        example: a1b2c3d4e5f6g7h8i9j0
        description: Your API authentication key
        schema:
          type: string
      - name: start_at
        in: query
        schema:
          type: string
          format: date
        required: true
        description: Start date in YYYY-MM-DD format
        example: '2023-01-01'
      - name: end_at
        in: query
        schema:
          type: string
          format: date
        required: true
        description: End date in YYYY-MM-DD format
        example: '2023-12-31'
      responses:
        '200':
          description: cities found
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    description: Array of countries and their visited cities
                    example:
                    - country: Germany
                      cities:
                      - city: Berlin
                        points: 4394
                        timestamp: 1724868369
                        stayed_for: 24490
                      - city: Munich
                        points: 2156
                        timestamp: 1724782369
                        stayed_for: 12450
                    - country: France
                      cities:
                      - city: Paris
                        points: 3267
                        timestamp: 1724695969
                        stayed_for: 18720
                    items:
                      type: object
                      properties:
                        country:
                          type: string
                          example: Germany
                        cities:
                          type: array
                          items:
                            type: object
                            properties:
                              city:
                                type: string
                                example: Berlin
                              points:
                                type: integer
                                example: 4394
                                description: Number of points in the city
                              timestamp:
                                type: integer
                                example: 1724868369
                                description: Timestamp of the last point in the city
                                  in seconds since Unix epoch
                              stayed_for:
                                type: integer
                                example: 24490
                                description: Number of minutes the user stayed in
                                  the city
        '400':
          description: bad request - missing parameters
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: 'Missing required parameters: start_at, end_at'
  "/api/v1/health":
    get:
      summary: Retrieves application status
      tags:
      - Health
      responses:
        '200':
          description: Healthy
          headers:
            X-Dawarich-Response:
              schema:
                type: string
                example: Hey, I'm alive!
              required: true
              description: Depending on the authentication status of the request,
                the response will be different. If the request is authenticated, the
                response will be 'Hey, I'm alive and authenticated!'. If the request
                is not authenticated, the response will be 'Hey, I'm alive!'.
            X-Dawarich-Version:
              schema:
                type: string
                example: 1.0.0
              required: true
              description: 'The version of the application, for example: 1.0.0'
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
  "/api/v1/overland/batches":
    post:
      summary: Creates a batch of points
      tags:
      - Batches
      parameters:
      - name: api_key
        in: query
        required: true
        description: API Key
        schema:
          type: string
      responses:
        '201':
          description: Batch of points created
        '401':
          description: Unauthorized
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                locations:
                  type: array
                  items:
                    type: object
                    properties:
                      type:
                        type: string
                        example: Feature
                      geometry:
                        type: object
                        properties:
                          type:
                            type: string
                            example: Point
                          coordinates:
                            type: array
                            items:
                              type: number
                            example:
                            - 13.356718
                            - 52.502397
                      properties:
                        type: object
                        properties:
                          timestamp:
                            type: string
                            example: '2021-06-01T12:00:00Z'
                            description: Timestamp in ISO 8601 format
                          altitude:
                            type: number
                            example: 0
                            description: Altitude in meters
                          speed:
                            type: number
                            example: 0
                            description: Speed in meters per second
                          horizontal_accuracy:
                            type: number
                            example: 0
                            description: Horizontal accuracy in meters
                          vertical_accuracy:
                            type: number
                            example: 0
                            description: Vertical accuracy in meters
                          motion:
                            type: array
                            items:
                              type: string
                            example:
                            - walking
                            - running
                            - driving
                            - cycling
                            - stationary
                            description: 'Motion type, for example: automotive_navigation,
                              fitness, other_navigation or other'
                          activity:
                            type: string
                            example: unknown
                            description: 'Activity type, for example: automotive_navigation,
                              fitness, other_navigation or other'
                          desired_accuracy:
                            type: number
                            example: 0
                            description: Desired accuracy in meters
                          deferred:
                            type: number
                            example: 0
                            description: the distance in meters to defer location
                              updates
                          significant_change:
                            type: string
                            example: disabled
                            description: a significant change mode, disabled, enabled
                              or exclusive
                          locations_in_payload:
                            type: number
                            example: 1
                            description: the number of locations in the payload
                          device_id:
                            type: string
                            example: 'iOS device #166'
                            description: the device id
                          unique_id:
                            type: string
                            example: '1234567890'
                            description: the device's Unique ID as set by Apple
                          wifi:
                            type: string
                            example: unknown
                            description: the WiFi network name
                          battery_state:
                            type: string
                            example: unknown
                            description: the battery state, unknown, unplugged, charging
                              or full
                          battery_level:
                            type: number
                            example: 0
                            description: the battery level percentage, from 0 to 1
                    required:
                    - geometry
                    - properties
            examples:
              '0':
                summary: Creates a batch of points
                value:
                  locations:
                  - type: Feature
                    geometry:
                      type: Point
                      coordinates:
                      - 13.356718
                      - 52.502397
                    properties:
                      timestamp: '2021-06-01T12:00:00Z'
                      altitude: 0
                      speed: 0
                      horizontal_accuracy: 0
                      vertical_accuracy: 0
                      motion: []
                      pauses: false
                      activity: unknown
                      desired_accuracy: 0
                      deferred: 0
                      significant_change: unknown
                      locations_in_payload: 1
                      device_id: 'iOS device #166'
                      unique_id: '1234567890'
                      wifi: unknown
                      battery_state: unknown
                      battery_level: 0
  "/api/v1/owntracks/points":
    post:
      summary: Creates a point
      tags:
      - Points
      parameters:
      - name: api_key
        in: query
        required: true
        description: API Key
        schema:
          type: string
      responses:
        '200':
          description: Point created
        '401':
          description: Unauthorized
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                batt:
                  type: number
                  description: Device battery level (percentage)
                lon:
                  type: number
                  description: Longitude coordinate
                acc:
                  type: number
                  description: Accuracy of position in meters
                bs:
                  type: number
                  description: Battery status (0=unknown, 1=unplugged, 2=charging,
                    3=full)
                inrids:
                  type: array
                  items:
                    type: string
                  description: Array of region IDs device is currently in
                BSSID:
                  type: string
                  description: Connected WiFi access point MAC address
                SSID:
                  type: string
                  description: Connected WiFi network name
                vac:
                  type: number
                  description: Vertical accuracy in meters
                inregions:
                  type: array
                  items:
                    type: string
                  description: Array of region names device is currently in
                lat:
                  type: number
                  description: Latitude coordinate
                topic:
                  type: string
                  description: MQTT topic in format owntracks/user/device
                t:
                  type: string
                  description: Type of message (p=position, c=circle, etc)
                conn:
                  type: string
                  description: Connection type (w=wifi, m=mobile, o=offline)
                m:
                  type: number
                  description: Motion state (0=stopped, 1=moving)
                tst:
                  type: number
                  description: Timestamp in Unix epoch time
                alt:
                  type: number
                  description: Altitude in meters
                _type:
                  type: string
                  description: Internal message type (usually "location")
                tid:
                  type: string
                  description: Tracker ID used to display the initials of a user
                _http:
                  type: boolean
                  description: Whether message was sent via HTTP (true) or MQTT (false)
                ghash:
                  type: string
                  description: Geohash of location
                isorcv:
                  type: string
                  description: ISO 8601 timestamp when message was received
                isotst:
                  type: string
                  description: ISO 8601 timestamp of the location fix
                disptst:
                  type: string
                  description: Human-readable timestamp of the location fix
              required:
              - lat
              - lon
              - tst
              - _type
            examples:
              '0':
                summary: Creates a point
                value:
                  batt: 85
                  lon: -74.006
                  acc: 8
                  bs: 2
                  inrids:
                  - 5f1d1b
                  BSSID: b0:f2:8:45:94:33
                  SSID: Home Wifi
                  vac: 3
                  inregions:
                  - home
                  lat: 40.7128
                  topic: owntracks/jane/iPhone 12 Pro
                  t: p
                  conn: w
                  m: 1
                  tst: 1706965203
                  alt: 41
                  _type: location
                  tid: RO
                  _http: true
                  ghash: u33d773
                  isorcv: '2024-02-03T13:00:03Z'
                  isotst: '2024-02-03T13:00:03Z'
                  disptst: '2024-02-03 13:00:03'
  "/api/v1/photos":
    get:
      summary: Lists photos
      tags:
      - Photos
      parameters:
      - name: api_key
        in: query
        required: true
        schema:
          type: string
      - name: start_date
        in: query
        required: true
        description: Start date in ISO8601 format, e.g. 2024-01-01
        schema:
          type: string
      - name: end_date
        in: query
        required: true
        description: End date in ISO8601 format, e.g. 2024-01-02
        schema:
          type: string
      responses:
        '200':
          description: photos found
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                    latitude:
                      type: number
                      format: float
                    longitude:
                      type: number
                      format: float
                    localDateTime:
                      type: string
                      format: date-time
                    originalFileName:
                      type: string
                    city:
                      type: string
                    state:
                      type: string
                    country:
                      type: string
                    type:
                      type: string
                      enum:
                      - image
                      - video
                    orientation:
                      type: string
                      enum:
                      - portrait
                      - landscape
                    source:
                      type: string
                      enum:
                      - immich
                      - photoprism
                  required:
                  - id
                  - latitude
                  - longitude
                  - localDateTime
                  - originalFileName
                  - city
                  - state
                  - country
                  - type
                  - source
  "/api/v1/photos/{id}/thumbnail":
    get:
      summary: Retrieves a photo
      tags:
      - Photos
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      - name: api_key
        in: query
        required: true
        schema:
          type: string
      - name: source
        in: query
        required: true
        schema:
          type: string
      responses:
        '200':
          description: photo found
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  latitude:
                    type: number
                    format: float
                  longitude:
                    type: number
                    format: float
                  localDateTime:
                    type: string
                    format: date-time
                  originalFileName:
                    type: string
                  city:
                    type: string
                  state:
                    type: string
                  country:
                    type: string
                  type:
                    type: string
                    enum:
                    - IMAGE
                    - VIDEO
                    - image
                    - video
                    - raw
                    - live
                    - animated
                  orientation:
                    type: string
                    enum:
                    - portrait
                    - landscape
                  source:
                    type: string
                    enum:
                    - immich
                    - photoprism
        '404':
          description: photo not found
  "/api/v1/places":
    get:
      summary: Retrieves all places for the authenticated user
      tags:
      - Places
      parameters:
      - name: api_key
        in: query
        required: true
        description: API key for authentication
        schema:
          type: string
      - name: tag_ids
        in: query
        items:
          type: integer
        required: false
        description: Filter places by tag IDs
        schema:
          type: array
      responses:
        '200':
          description: places found
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: integer
                    name:
                      type: string
                    latitude:
                      type: number
                      format: float
                    longitude:
                      type: number
                      format: float
                    source:
                      type: string
                    icon:
                      type: string
                      nullable: true
                    color:
                      type: string
                      nullable: true
                    visits_count:
                      type: integer
                    created_at:
                      type: string
                      format: date-time
                    tags:
                      type: array
                      items:
                        type: object
                        properties:
                          id:
                            type: integer
                          name:
                            type: string
                          icon:
                            type: string
                          color:
                            type: string
                  required:
                  - id
                  - name
                  - latitude
                  - longitude
        '401':
          description: unauthorized
    post:
      summary: Creates a place
      tags:
      - Places
      parameters:
      - name: api_key
        in: query
        required: true
        description: API key for authentication
        schema:
          type: string
      responses:
        '201':
          description: place created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  latitude:
                    type: number
                    format: float
                  longitude:
                    type: number
                    format: float
                  source:
                    type: string
                  icon:
                    type: string
                    nullable: true
                  color:
                    type: string
                    nullable: true
                  visits_count:
                    type: integer
                  created_at:
                    type: string
                    format: date-time
                  tags:
                    type: array
        '422':
          description: invalid request
        '401':
          description: unauthorized
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                latitude:
                  type: number
                  format: float
                longitude:
                  type: number
                  format: float
                source:
                  type: string
                tag_ids:
                  type: array
                  items:
                    type: integer
              required:
              - name
              - latitude
              - longitude
  "/api/v1/places/nearby":
    get:
      summary: Searches for nearby places using Photon geocoding API
      tags:
      - Places
      parameters:
      - name: api_key
        in: query
        required: true
        description: API key for authentication
        schema:
          type: string
      - name: latitude
        in: query
        format: float
        required: true
        description: Latitude coordinate
        schema:
          type: number
      - name: longitude
        in: query
        format: float
        required: true
        description: Longitude coordinate
        schema:
          type: number
      - name: radius
        in: query
        format: float
        required: false
        description: 'Search radius in kilometers (default: 0.5)'
        schema:
          type: number
      - name: limit
        in: query
        required: false
        description: 'Maximum number of results (default: 10)'
        schema:
          type: integer
      responses:
        '200':
          description: nearby places found
          content:
            application/json:
              schema:
                type: object
                properties:
                  places:
                    type: array
                    items:
                      type: object
                      properties:
                        name:
                          type: string
                        latitude:
                          type: number
                          format: float
                        longitude:
                          type: number
                          format: float
                        distance:
                          type: number
                          format: float
                        type:
                          type: string
        '401':
          description: unauthorized
  "/api/v1/places/{id}":
    parameters:
    - name: id
      in: path
      description: Place ID
      required: true
      schema:
        type: integer
    get:
      summary: Retrieves a specific place
      tags:
      - Places
      parameters:
      - name: api_key
        in: query
        required: true
        description: API key for authentication
        schema:
          type: string
      responses:
        '200':
          description: place found
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  latitude:
                    type: number
                    format: float
                  longitude:
                    type: number
                    format: float
                  source:
                    type: string
                  icon:
                    type: string
                    nullable: true
                  color:
                    type: string
                    nullable: true
                  visits_count:
                    type: integer
                  created_at:
                    type: string
                    format: date-time
                  tags:
                    type: array
        '404':
          description: place not found
        '401':
          description: unauthorized
    patch:
      summary: Updates a place
      tags:
      - Places
      parameters:
      - name: api_key
        in: query
        required: true
        description: API key for authentication
        schema:
          type: string
      responses:
        '200':
          description: place updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  latitude:
                    type: number
                    format: float
                  longitude:
                    type: number
                    format: float
                  tags:
                    type: array
        '404':
          description: place not found
        '422':
          description: invalid request
        '401':
          description: unauthorized
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                latitude:
                  type: number
                  format: float
                longitude:
                  type: number
                  format: float
                tag_ids:
                  type: array
                  items:
                    type: integer
    delete:
      summary: Deletes a place
      tags:
      - Places
      parameters:
      - name: api_key
        in: query
        required: true
        description: API key for authentication
        schema:
          type: string
      responses:
        '204':
          description: place deleted
        '404':
          description: place not found
        '401':
          description: unauthorized
  "/api/v1/points/tracked_months":
    get:
      summary: Returns list of tracked years and months
      tags:
      - Points
      parameters:
      - name: api_key
        in: query
        required: true
        description: API Key
        schema:
          type: string
      responses:
        '200':
          description: years and months found
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    year:
                      type: integer
                      description: Year in YYYY format
                    months:
                      type: array
                      items:
                        type: string
                        description: Three-letter month abbreviation
                  required:
                  - year
                  - months
                example:
                - year: 2024
                  months:
                  - Jan
                  - Feb
                  - Mar
                  - Apr
                  - May
                  - Jun
                  - Jul
                  - Aug
                  - Sep
                  - Oct
                  - Nov
                  - Dec
        '401':
          description: unauthorized
  "/api/v1/points":
    get:
      summary: Retrieves all points
      tags:
      - Points
      parameters:
      - name: api_key
        in: query
        required: true
        description: API Key
        schema:
          type: string
      - name: start_at
        in: query
        description: Start date (i.e. 2024-02-03T13:00:03Z or 2024-02-03)
        schema:
          type: string
      - name: end_at
        in: query
        description: End date (i.e. 2024-02-03T13:00:03Z or 2024-02-03)
        schema:
          type: string
      - name: page
        in: query
        required: false
        description: Page number
        schema:
          type: integer
      - name: per_page
        in: query
        required: false
        description: Number of points per page
        schema:
          type: integer
      - name: order
        in: query
        required: false
        description: Order of points, valid values are `asc` or `desc`
        schema:
          type: string
      responses:
        '200':
          description: points found
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: integer
                    battery_status:
                      type: number
                    ping:
                      type: number
                    battery:
                      type: number
                    tracker_id:
                      type: string
                    topic:
                      type: string
                    altitude:
                      type: number
                    longitude:
                      type: number
                    velocity:
                      type: number
                    trigger:
                      type: string
                    bssid:
                      type: string
                    ssid:
                      type: string
                    connection:
                      type: string
                    vertical_accuracy:
                      type: number
                    accuracy:
                      type: number
                    timestamp:
                      type: number
                    latitude:
                      type: number
                    mode:
                      type: number
                    inrids:
                      type: array
                      items:
                        type: string
                    in_regions:
                      type: array
                      items:
                        type: string
                    raw_data:
                      type: string
                    import_id:
                      type: string
                    city:
                      type: string
                    country:
                      type: string
                    created_at:
                      type: string
                    updated_at:
                      type: string
                    user_id:
                      type: integer
                    geodata:
                      type: string
                    visit_id:
                      type: string
    post:
      summary: Creates a batch of points
      tags:
      - Points
      parameters:
      - name: api_key
        in: query
        required: true
        description: API Key
        schema:
          type: string
      responses:
        '200':
          description: Batch of points being processed
        '401':
          description: Unauthorized
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                locations:
                  type: array
                  items:
                    type: object
                    properties:
                      type:
                        type: string
                      geometry:
                        type: object
                        properties:
                          type:
                            type: string
                            example: Point
                            description: the geometry type, always Point
                          coordinates:
                            type: array
                            items:
                              type: number
                              example:
                              - -122.40530871
                              - 37.74430413
                              description: the coordinates of the point, longitude
                                and latitude
                      properties:
                        type: object
                        properties:
                          timestamp:
                            type: string
                            example: '2025-01-17T21:03:01Z'
                            description: the timestamp of the point
                          horizontal_accuracy:
                            type: number
                            example: 5
                            description: the horizontal accuracy of the point in meters
                          vertical_accuracy:
                            type: number
                            example: -1
                            description: the vertical accuracy of the point in meters
                          altitude:
                            type: number
                            example: 0
                            description: the altitude of the point in meters
                          speed:
                            type: number
                            example: 92.088
                            description: the speed of the point in meters per second
                          speed_accuracy:
                            type: number
                            example: 0
                            description: the speed accuracy of the point in meters
                              per second
                          course_accuracy:
                            type: number
                            example: 0
                            description: the course accuracy of the point in degrees
                          track_id:
                            type: string
                            example: 799F32F5-89BB-45FB-A639-098B1B95B09F
                            description: the track id of the point set by the device
                          device_id:
                            type: string
                            example: 8D5D4197-245B-4619-A88B-2049100ADE46
                            description: the device id of the point set by the device
                    required:
                    - geometry
                    - properties
            examples:
              '0':
                summary: Creates a batch of points
                value:
                  locations:
                  - type: Feature
                    geometry:
                      type: Point
                      coordinates:
                      - -122.40530871
                      - 37.74430413
                    properties:
                      battery_state: full
                      battery_level: 0.7
                      wifi: dawarich_home
                      timestamp: '2025-01-17T21:03:01Z'
                      horizontal_accuracy: 5
                      vertical_accuracy: -1
                      altitude: 0
                      speed: 92.088
                      speed_accuracy: 0
                      course: 27.07
                      course_accuracy: 0
                      track_id: 799F32F5-89BB-45FB-A639-098B1B95B09F
                      device_id: 8D5D4197-245B-4619-A88B-2049100ADE46
  "/api/v1/points/{id}":
    delete:
      summary: Deletes a point
      tags:
      - Points
      parameters:
      - name: api_key
        in: query
        required: true
        description: API Key
        schema:
          type: string
      - name: id
        in: path
        required: true
        description: Point ID
        schema:
          type: string
      responses:
        '200':
          description: point deleted
  "/api/v1/settings":
    patch:
      summary: Updates user settings
      tags:
      - Settings
      parameters:
      - name: api_key
        in: query
        required: true
        description: API Key
        schema:
          type: string
      responses:
        '200':
          description: settings updated
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                route_opacity:
                  type: number
                  example: 60
                  description: Route opacity percentage (0-100)
                meters_between_routes:
                  type: number
                  example: 500
                  description: Minimum distance between routes in meters
                minutes_between_routes:
                  type: number
                  example: 30
                  description: Minimum time between routes in minutes
                fog_of_war_meters:
                  type: number
                  example: 50
                  description: Fog of war radius in meters
                time_threshold_minutes:
                  type: number
                  example: 30
                  description: Time threshold for grouping points in minutes
                merge_threshold_minutes:
                  type: number
                  example: 15
                  description: Threshold for merging nearby points in minutes
                preferred_map_layer:
                  type: string
                  example: OpenStreetMap
                  description: Preferred map layer/tile provider
                speed_colored_routes:
                  type: boolean
                  example: false
                  description: Whether to color routes based on speed
                points_rendering_mode:
                  type: string
                  example: raw
                  description: How to render points on the map (raw, heatmap, etc.)
                live_map_enabled:
                  type: boolean
                  example: true
                  description: Whether live map updates are enabled
                immich_url:
                  type: string
                  example: https://immich.example.com
                  description: Immich server URL for photo integration
                immich_api_key:
                  type: string
                  example: your-immich-api-key
                  description: API key for Immich photo service
                photoprism_url:
                  type: string
                  example: https://photoprism.example.com
                  description: PhotoPrism server URL for photo integration
                photoprism_api_key:
                  type: string
                  example: your-photoprism-api-key
                  description: API key for PhotoPrism photo service
                speed_color_scale:
                  type: string
                  example: viridis
                  description: Color scale for speed-colored routes
                fog_of_war_threshold:
                  type: number
                  example: 100
                  description: Fog of war threshold value
            examples:
              '0':
                summary: Updates user settings
                value:
                  settings:
                    route_opacity: 60
                    meters_between_routes: 500
                    minutes_between_routes: 30
                    fog_of_war_meters: 50
                    time_threshold_minutes: 30
                    merge_threshold_minutes: 15
                    preferred_map_layer: OpenStreetMap
                    speed_colored_routes: false
                    points_rendering_mode: raw
                    live_map_enabled: true
                    immich_url: https://immich.example.com
                    immich_api_key: your-immich-api-key
                    photoprism_url: https://photoprism.example.com
                    photoprism_api_key: your-photoprism-api-key
                    speed_color_scale: viridis
                    fog_of_war_threshold: 100
    get:
      summary: Retrieves user settings
      tags:
      - Settings
      parameters:
      - name: api_key
        in: query
        required: true
        description: API Key
        schema:
          type: string
      responses:
        '200':
          description: settings found
          content:
            application/json:
              schema:
                type: object
                properties:
                  settings:
                    type: object
                    properties:
                      route_opacity:
                        type: number
                        example: 60
                        description: Route opacity percentage (0-100)
                      meters_between_routes:
                        oneOf:
                        - type: number
                        - type: string
                        example: 500
                        description: Minimum distance between routes in meters
                      minutes_between_routes:
                        oneOf:
                        - type: number
                        - type: string
                        example: 30
                        description: Minimum time between routes in minutes
                      fog_of_war_meters:
                        oneOf:
                        - type: number
                        - type: string
                        example: 50
                        description: Fog of war radius in meters
                      time_threshold_minutes:
                        oneOf:
                        - type: number
                        - type: string
                        example: 30
                        description: Time threshold for grouping points in minutes
                      merge_threshold_minutes:
                        oneOf:
                        - type: number
                        - type: string
                        example: 15
                        description: Threshold for merging nearby points in minutes
                      preferred_map_layer:
                        type: string
                        example: OpenStreetMap
                        description: Preferred map layer/tile provider
                      speed_colored_routes:
                        type: boolean
                        example: false
                        description: Whether to color routes based on speed
                      points_rendering_mode:
                        type: string
                        example: raw
                        description: How to render points on the map (raw, heatmap,
                          etc.)
                      live_map_enabled:
                        type: boolean
                        example: true
                        description: Whether live map updates are enabled
                      immich_url:
                        oneOf:
                        - type: string
                        - type: 'null'
                        example: https://immich.example.com
                        description: Immich server URL for photo integration
                      immich_api_key:
                        oneOf:
                        - type: string
                        - type: 'null'
                        example: your-immich-api-key
                        description: API key for Immich photo service
                      photoprism_url:
                        oneOf:
                        - type: string
                        - type: 'null'
                        example: https://photoprism.example.com
                        description: PhotoPrism server URL for photo integration
                      photoprism_api_key:
                        oneOf:
                        - type: string
                        - type: 'null'
                        example: your-photoprism-api-key
                        description: API key for PhotoPrism photo service
                      speed_color_scale:
                        oneOf:
                        - type: string
                        - type: 'null'
                        example: viridis
                        description: Color scale for speed-colored routes
                      fog_of_war_threshold:
                        oneOf:
                        - type: number
                        - type: string
                        - type: 'null'
                        example: 100
                        description: Fog of war threshold value
  "/api/v1/stats":
    get:
      summary: Retrieves all stats
      tags:
      - Stats
      parameters:
      - name: api_key
        in: query
        required: true
        description: API Key
        schema:
          type: string
      responses:
        '200':
          description: stats found
          content:
            application/json:
              schema:
                type: object
                properties:
                  totalDistanceKm:
                    type: number
                  totalPointsTracked:
                    type: number
                  totalReverseGeocodedPoints:
                    type: number
                  totalCountriesVisited:
                    type: number
                  totalCitiesVisited:
                    type: number
                  yearlyStats:
                    type: array
                    items:
                      type: object
                      properties:
                        year:
                          type: integer
                        totalDistanceKm:
                          type: number
                        totalCountriesVisited:
                          type: number
                        totalCitiesVisited:
                          type: number
                        monthlyDistanceKm:
                          type: object
                          properties:
                            january:
                              type: number
                            february:
                              type: number
                            march:
                              type: number
                            april:
                              type: number
                            may:
                              type: number
                            june:
                              type: number
                            july:
                              type: number
                            august:
                              type: number
                            september:
                              type: number
                            october:
                              type: number
                            november:
                              type: number
                            december:
                              type: number
                      required:
                      - year
                      - totalDistanceKm
                      - totalCountriesVisited
                      - totalCitiesVisited
                      - monthlyDistanceKm
                required:
                - totalDistanceKm
                - totalPointsTracked
                - totalReverseGeocodedPoints
                - totalCountriesVisited
                - totalCitiesVisited
                - yearlyStats
  "/api/v1/users/me":
    get:
      summary: Returns the current user
      tags:
      - Users
      security:
      - bearer_auth: []
      parameters:
      - name: Authorization
        in: header
        required: true
        description: 'Bearer token in the format: Bearer {api_key}'
        schema:
          type: string
      responses:
        '200':
          description: user found
  "/api/v1/visits":
    get:
      summary: List visits
      tags:
      - Visits
      parameters:
      - name: Authorization
        in: header
        required: true
        description: Bearer token
        schema:
          type: string
      - name: start_at
        in: query
        required: false
        description: Start date (ISO 8601)
        schema:
          type: string
      - name: end_at
        in: query
        required: false
        description: End date (ISO 8601)
        schema:
          type: string
      - name: selection
        in: query
        required: false
        description: Set to "true" for area-based search
        schema:
          type: string
      - name: sw_lat
        in: query
        required: false
        description: Southwest latitude for area search
        schema:
          type: number
      - name: sw_lng
        in: query
        required: false
        description: Southwest longitude for area search
        schema:
          type: number
      - name: ne_lat
        in: query
        required: false
        description: Northeast latitude for area search
        schema:
          type: number
      - name: ne_lng
        in: query
        required: false
        description: Northeast longitude for area search
        schema:
          type: number
      responses:
        '200':
          description: visits found
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: integer
                    name:
                      type: string
                    status:
                      type: string
                      enum:
                      - suggested
                      - confirmed
                      - declined
                    started_at:
                      type: string
                      format: datetime
                    ended_at:
                      type: string
                      format: datetime
                    duration:
                      type: integer
                      description: Duration in minutes
                    place:
                      type: object
                      properties:
                        id:
                          type: integer
                        name:
                          type: string
                        latitude:
                          type: number
                        longitude:
                          type: number
                        city:
                          type: string
                        country:
                          type: string
                  required:
                  - id
                  - name
                  - status
                  - started_at
                  - ended_at
                  - duration
        '401':
          description: unauthorized
    post:
      summary: Create visit
      tags:
      - Visits
      parameters:
      - name: Authorization
        in: header
        required: true
        description: Bearer token
        schema:
          type: string
      responses:
        '200':
          description: visit created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  status:
                    type: string
                  started_at:
                    type: string
                    format: datetime
                  ended_at:
                    type: string
                    format: datetime
                  duration:
                    type: integer
                  place:
                    type: object
                    properties:
                      id:
                        type: integer
                      name:
                        type: string
                      latitude:
                        type: number
                      longitude:
                        type: number
        '422':
          description: invalid request
        '401':
          description: unauthorized
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                visit:
                  type: object
                  properties:
                    name:
                      type: string
                    latitude:
                      type: number
                    longitude:
                      type: number
                    started_at:
                      type: string
                      format: datetime
                    ended_at:
                      type: string
                      format: datetime
                  required:
                  - name
                  - latitude
                  - longitude
                  - started_at
                  - ended_at
  "/api/v1/visits/{id}":
    patch:
      summary: Update visit
      tags:
      - Visits
      parameters:
      - name: id
        in: path
        required: true
        description: Visit ID
        schema:
          type: integer
      - name: Authorization
        in: header
        required: true
        description: Bearer token
        schema:
          type: string
      responses:
        '200':
          description: visit updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  status:
                    type: string
                  started_at:
                    type: string
                    format: datetime
                  ended_at:
                    type: string
                    format: datetime
                  duration:
                    type: integer
                  place:
                    type: object
        '404':
          description: visit not found
        '401':
          description: unauthorized
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                visit:
                  type: object
                  properties:
                    name:
                      type: string
                    place_id:
                      type: integer
                    status:
                      type: string
                      enum:
                      - suggested
                      - confirmed
                      - declined
    delete:
      summary: Delete visit
      tags:
      - Visits
      parameters:
      - name: id
        in: path
        required: true
        description: Visit ID
        schema:
          type: integer
      - name: Authorization
        in: header
        required: true
        description: Bearer token
        schema:
          type: string
      responses:
        '204':
          description: visit deleted
        '404':
          description: visit not found
        '401':
          description: unauthorized
  "/api/v1/visits/{id}/possible_places":
    get:
      summary: Get possible places for visit
      tags:
      - Visits
      parameters:
      - name: id
        in: path
        required: true
        description: Visit ID
        schema:
          type: integer
      - name: Authorization
        in: header
        required: true
        description: Bearer token
        schema:
          type: string
      responses:
        '200':
          description: possible places found
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: integer
                    name:
                      type: string
                    latitude:
                      type: number
                    longitude:
                      type: number
                    city:
                      type: string
                    country:
                      type: string
        '404':
          description: visit not found
        '401':
          description: unauthorized
  "/api/v1/visits/merge":
    post:
      summary: Merge visits
      tags:
      - Visits
      parameters:
      - name: Authorization
        in: header
        required: true
        description: Bearer token
        schema:
          type: string
      responses:
        '200':
          description: visits merged
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  status:
                    type: string
                  started_at:
                    type: string
                    format: datetime
                  ended_at:
                    type: string
                    format: datetime
                  duration:
                    type: integer
                  place:
                    type: object
        '422':
          description: invalid request
        '401':
          description: unauthorized
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                visit_ids:
                  type: array
                  items:
                    type: integer
                  minItems: 2
                  description: Array of visit IDs to merge (minimum 2)
              required:
              - visit_ids
  "/api/v1/visits/bulk_update":
    post:
      summary: Bulk update visits
      tags:
      - Visits
      parameters:
      - name: Authorization
        in: header
        required: true
        description: Bearer token
        schema:
          type: string
      responses:
        '200':
          description: visits updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  updated_count:
                    type: integer
        '422':
          description: invalid request
        '401':
          description: unauthorized
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                visit_ids:
                  type: array
                  items:
                    type: integer
                  description: Array of visit IDs to update
                status:
                  type: string
                  enum:
                  - suggested
                  - confirmed
                  - declined
                  description: New status for the visits
              required:
              - visit_ids
              - status
servers:
- url: http://{defaultHost}
  variables:
    defaultHost:
      default: localhost:3000
