openapi: '3.1.0'
info:
  title: Motionworks API - Pathcast (Paths, Viewsheds, Traffic)
  version: 2.0.0
  description: >
    Per-media-unit paths, viewshed polygons, and hourly vehicle + pedestrian
    traffic measurements. Every face (Motionworks place of place_type "Face")
    has one viewshed and one or more paths. Traffic is reported at
    (path x year x month x day_type x hour) granularity with day_type =
    1 (Mon–Thu), 2 (Fri), 3 (Sat), 4 (Sun).
    Source: https://docs.mworks.com/docs/pathcast-by-date
            https://docs.mworks.com/docs/pathcast-path-library
            https://docs.mworks.com/docs/pathcast-viewshed-library


    For vector-tile delivery of Pathcast data (drop tiles directly into
    MapLibre or Mapbox GL), see the
    [Paths Tiles page](./paths/) (ADR-027).
  contact:
    name: Motionworks AI
    url: https://mworks.com
    email: api@mworks.com

servers:
  - url: https://api.mworks.com/v2
    description: Production

security:
  - apiKey: []

components:
  securitySchemes:
    apiKey:
      type: apiKey
      name: X-API-Key
      in: header

  schemas:
    Path:
      type: object
      additionalProperties: false
      required:
        - place_id
        - path_id
        - audit_status_id
        - audit_status
        - mode
        - funcclass
        - path
        - gate_veh
        - gate_ped
        - modified
      x-motionworks-status: production
      x-motionworks-source: pathcast-path-library
      x-motionworks-source-doc: https://docs.mworks.com/docs/pathcast-path-library
      properties:
        place_id:
          type: integer
          description: The face (place) this path serves.
        path_id:
          type: string
          description: Opaque hex path identifier.
        audit_status_id:
          type: integer
          enum: [0, 4, 7, 9, 12, 14]
        audit_status:
          type: string
          enum:
            - Assigned
            - Audited
            - Removed from Audit
            - Automated
            - Published - Third Party
            - Removed from Publishing
        mode:
          type: string
          enum: [B, P]
          description: B = Vehicular+Pedestrian, P = Pedestrian Only
        funcclass:
          type: integer
          description: HERE functional class for the underlying roadway.
        path:
          type: string
          description: Path geometry as WKT LINESTRING.
        gate_veh:
          type: string
          description: Vehicle measurement gate as WKT LINESTRING.
        gate_ped:
          type: string
          description: Pedestrian measurement gate as WKT LINESTRING.
        modified:
          type: string

    Viewshed:
      type: object
      additionalProperties: false
      required:
        - place_id
        - audit_status_id
        - lon
        - lat
        - orientation
        - height_in
        - width_in
        - digital
        - modified
        - max_distance_m
        - geography
      x-motionworks-status: production
      x-motionworks-source: pathcast-viewshed-library
      x-motionworks-source-doc: https://docs.mworks.com/docs/pathcast-viewshed-library
      properties:
        place_id:
          type: integer
        audit_status_id:
          type: integer
        lon:
          type: number
          format: double
        lat:
          type: number
          format: double
        orientation:
          type: number
          description: Cardinal orientation in degrees (0=N, 180=S).
        height_in:
          type: number
          description: Display height in inches.
        width_in:
          type: number
          description: Display width in inches.
        digital:
          type: boolean
        modified:
          type: string
        max_distance_m:
          type: number
          description: Maximum viewshed width in meters.
        geography:
          type: string
          description: Viewshed polygon as WKT POLYGON.

    PathTraffic:
      type: object
      additionalProperties: false
      required:
        - place_id
        - path_id
        - audit_status_id
        - year
        - month
        - day_type
        - hour
        - days
        - vehicles
        - vehicle_observations
        - average_speed
        - pedestrians
        - pedestrian_observations
        - is_active
      x-motionworks-status: production
      x-motionworks-source: pathcast-by-date
      x-motionworks-source-doc: https://docs.mworks.com/docs/pathcast-by-date
      properties:
        place_id:
          type: integer
        path_id:
          type: string
        audit_status_id:
          type: integer
          enum: [0, 4, 7, 9, 12, 14]
        year:
          type: integer
        month:
          type: integer
          minimum: 1
          maximum: 12
        day_type:
          type: integer
          enum: [1, 2, 3, 4]
          description: 1=Mon-Thu, 2=Fri, 3=Sat, 4=Sun
        hour:
          type: integer
          minimum: 0
          maximum: 23
        days:
          type: integer
          description: Days in aggregation bucket (e.g. 5 Sundays in Oct 2024).
        vehicles:
          type: integer
          description: Estimated vehicles crossing the vehicle gate during the hour × day_type.
        vehicle_observations:
          type: integer
          description: Raw StreetLight observations used to generate the estimate.
        average_speed:
          type: integer
          description: Average speed in mph along the entire path.
        pedestrians:
          type: integer
          nullable: true
          x-motionworks-status: research-preview
          description: >
            [Research Preview] Estimated pedestrians. Currently null for
            periods after April 2022 pending methodology refinement.
        pedestrian_observations:
          type: integer
          nullable: true
          x-motionworks-status: research-preview
        is_active:
          type: boolean

    Pagination:
      type: object
      properties:
        cursor:
          type: string
          nullable: true
        has_more:
          type: boolean
        total:
          type: integer

    Provenance:
      type: object
      # Invariant F2 — is_focused <=> measurement_method (ADR-033 §2.3).
      # JSON Schema 2020-12 conditional (OpenAPI 3.1 is a 2020-12 dialect).
      # Both fields stay OPTIONAL and independently omittable: the `if`
      # only fires when BOTH are present, so an envelope carrying only
      # `is_focused`, only `measurement_method`, or neither still validates
      # — which keeps every non-Placecast product's existing envelope valid.
      # Only the disagreeing combination is unrepresentable. Mirrors the
      # .refine() guard on ProvenanceSchema in
      # packages/types/src/schemas/provenance.ts.
      if:
        required: [is_focused, measurement_method]
      then:
        oneOf:
          - properties:
              is_focused:
                const: true
              measurement_method:
                const: direct
          - properties:
              is_focused:
                const: false
              measurement_method:
                const: estimated
      properties:
        source:
          type: string
        source_doc:
          type: string
          format: uri
        methodology_version:
          type: string
        data_vintage:
          type: string
          format: date
        data_freshness:
          type: string
          enum: [hourly, daily, weekly, monthly, annually, on-demand, static]
        data_latency_days:
          type: integer
        data_maturity:
          type: string
          enum: [production, research-preview, synthetic-only, roadmap]
        is_focused:
          type: boolean
        measurement_method:
          type: string
          enum: [direct, estimated]
          description: >
            Optional explicit measurement provenance. "direct" means the
            place is focused and its statistics are measured; "estimated"
            means the place is unfocused and its statistics use peer-group
            inference. When both this field and is_focused are present they
            must agree (is_focused=true => direct, false => estimated).

    Meta:
      type: object
      properties:
        request_id:
          type: string
        credits_used:
          type: integer
        credits_remaining:
          type: integer
        product:
          type: string
        version:
          type: string
        provenance:
          $ref: '#/components/schemas/Provenance'

    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
            status:
              type: integer
            request_id:
              type: string
            product:
              type: string
            docs_url:
              type: string

paths:
  /pathcast/paths/{path_id}:
    get:
      operationId: getPath
      summary: Get a single Path record
      x-credit-cost: 100
      x-motionworks-status: production
      x-motionworks-source-doc: https://docs.mworks.com/docs/pathcast-path-library
      parameters:
        - name: path_id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Path record
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Path'
                  meta:
                    $ref: '#/components/schemas/Meta'
        '404':
          description: Path not found

  /pathcast/faces/{place_id}/paths:
    get:
      operationId: listFacePaths
      summary: List all paths for a face (viewshed)
      x-credit-cost: 100
      x-motionworks-status: production
      x-motionworks-source-doc: https://docs.mworks.com/docs/pathcast-path-library
      parameters:
        - name: place_id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Array of paths
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Path'
                  meta:
                    $ref: '#/components/schemas/Meta'

  /pathcast/faces/{place_id}/viewshed:
    get:
      operationId: getFaceViewshed
      summary: Get the viewshed polygon + display metadata for a face
      x-credit-cost: 100
      x-motionworks-status: production
      x-motionworks-source-doc: https://docs.mworks.com/docs/pathcast-viewshed-library
      parameters:
        - name: place_id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Viewshed record
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Viewshed'
                  meta:
                    $ref: '#/components/schemas/Meta'

  /pathcast/paths/{path_id}/traffic:
    get:
      operationId: getPathTraffic
      summary: Hourly vehicle + pedestrian traffic for a path
      description: >
        Returns one or more PathTraffic rows. Omit any filter to aggregate on
        that axis — e.g. omit `hour` to return all 24 hours.
      x-credit-cost: 100
      x-motionworks-status: production
      x-motionworks-source-doc: https://docs.mworks.com/docs/pathcast-by-date
      parameters:
        - name: path_id
          in: path
          required: true
          schema:
            type: string
        - name: year
          in: query
          schema:
            type: integer
        - name: month
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 12
        - name: day_type
          in: query
          schema:
            type: integer
            enum: [1, 2, 3, 4]
        - name: hour
          in: query
          schema:
            type: integer
            minimum: 0
            maximum: 23
      responses:
        '200':
          description: Array of PathTraffic rows matching the filter
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PathTraffic'
                  meta:
                    $ref: '#/components/schemas/Meta'

  /pathcast/paths/{path_id}/history:
    get:
      operationId: getPathHistory
      summary: Historical traffic for a path across a date range
      x-credit-cost: 100
      x-motionworks-status: production
      x-motionworks-source-doc: https://docs.mworks.com/docs/pathcast-by-date
      parameters:
        - name: path_id
          in: path
          required: true
          schema:
            type: string
        - name: start_date
          in: query
          schema:
            type: string
            format: date
        - name: end_date
          in: query
          schema:
            type: string
            format: date
      responses:
        '200':
          description: Array of PathTraffic rows across the date range
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PathTraffic'
                  meta:
                    $ref: '#/components/schemas/Meta'
