openapi: '3.1.0'
info:
  title: Motionworks API - Placecast (Foot Traffic)
  version: 2.0.0
  description: >
    Four products under the Placecast family, each exposing a different
    temporal resolution or analysis type:

      /v2/placecast/profiles       — Weekly 6-wk rolling visits, dwell, activities (15-day latency)
      /v2/placecast/by-date        — Hourly visits + occupancy per month per daytype (30-day latency)
      /v2/placecast/trade-areas    — Home-geography of visitors by month / daytype / daypart
      /v2/placecast/select         — On-demand scenario for specific date-time windows

    Sources:
      https://docs.mworks.com/docs/placecast-profiles
      https://docs.mworks.com/docs/placecast-by-date
      https://docs.mworks.com/docs/placecast-trade-areas
      https://docs.mworks.com/docs/placecast-select
  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:
    VisitsCi:
      type: array
      items:
        type: integer
      minItems: 2
      maxItems: 2
      description: >
        90% confidence interval [lower, upper]. Derived from peer-group
        empirical quantiles. Not user-configurable.

    PlacecastReliability:
      type: object
      description: >
        4-score data-quality assessment (replaces the invented A/B/C/D/U
        enum from the v2 scaffold). Each score is 0–1 where 0 = behaves
        as expected vs peer group, 1 = significant outlier.
        is_focused = false means stats are estimated rather than measured.
      x-motionworks-status: production
      x-motionworks-source: placecast-validation
      x-motionworks-source-doc: https://docs.mworks.com/docs/placecast-validation
      properties:
        visit_score:
          type: number
          minimum: 0
          maximum: 1
        dwell_score:
          type: number
          minimum: 0
          maximum: 1
        profile_score:
          type: number
          minimum: 0
          maximum: 1
        visitor_distance_score:
          type: number
          minimum: 0
          maximum: 1
        is_focused:
          type: boolean
        methodology_version:
          type: string

    PlacecastProfile:
      type: object
      x-motionworks-status: production
      x-motionworks-source: placecast-profiles
      x-motionworks-source-doc: https://docs.mworks.com/docs/placecast-profiles
      properties:
        place_id:
          type: integer
        name:
          type: string
        place_type_id:
          type: integer
        place_type:
          type: string
        place_audit_status:
          type: string
        place_modified_date:
          type: string
          format: date
        published_date:
          type: string
          format: date
          description: Always a Monday. 6-week rolling averages published weekly.
        visits:
          type: integer
          description: >
            Weekly visits — ROLLING AVERAGE, not daily. This is the 6-week
            rolling mean, published each Monday on a 15-day latency.
        dropoffs:
          type: integer
        activities:
          type: integer
          description: activities = visits + dropoffs
        passbys:
          type: integer
        stays:
          type: integer
        visits_ci:
          $ref: '#/components/schemas/VisitsCi'
        visits_observations:
          type: integer
        imputed:
          type: boolean
        visits_avg_dwell:
          type: number
          description: Average dwell in minutes (ignores residents + workers).
        activities_dwell_threshold:
          type: number
        visits_frequency_per_person:
          type: number
        visits_unique_persons:
          type: integer
        visits_unique_long_trips:
          type: integer
        city:
          type: string
        state:
          type: string
        lat:
          type: number
        lon:
          type: number
        reliability:
          $ref: '#/components/schemas/PlacecastReliability'

    PlacecastByDate:
      type: object
      x-motionworks-status: production
      x-motionworks-source: placecast-by-date
      x-motionworks-source-doc: https://docs.mworks.com/docs/placecast-by-date
      properties:
        place_id:
          type: string
        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
        visits:
          type: number
        visits_age05plus:
          type: number
        visits_age18plus:
          type: number
        visits_departures:
          type: number
          nullable: true
          description: Airport-only. Null for non-airport places.
        visits_transfers:
          type: number
          nullable: true
        visits_arrivals:
          type: number
          nullable: true
        occupancy:
          type: number
          description: Average persons present during the hour.
        occupancy_age05plus:
          type: number
        occupancy_age18plus:
          type: number
        visits_avg_dwell:
          type: number
          description: Average dwell in hours (NOT minutes — By Date uses hours).
        visits_dwell_threshold:
          type: number
        dropoffs:
          type: number
        passbys:
          type: number
        activities:
          type: number
        exposures:
          type: number
          description: activities + passbys

    PlacecastTradeArea:
      type: object
      x-motionworks-status: production
      x-motionworks-source: placecast-trade-areas
      x-motionworks-source-doc: https://docs.mworks.com/docs/placecast-trade-areas
      properties:
        place_id:
          type: string
        homes_place_id:
          type: string
          description: Parent/focused place for unfocused places.
        geography_id:
          type: string
          description: >
            US Census block group, county, or Canadian equivalent.
            Regional refs (county/province) sum to 100% of visits;
            neighbourhood refs (<50mi) sum to <100%.
        prizm_segment:
          type: string
          nullable: true
          description: Only populated for regional geography rows.
        year:
          type: integer
        month:
          type: integer
          minimum: 1
          maximum: 12
        day_type:
          type: integer
          enum: [1, 2, 3, 4]
        day_part:
          type: integer
          enum: [1, 2, 3, 4, 5]
          description: 1=Overnight(00-06), 2=Morning drive(06-10), 3=Midday(10-15), 4=Afternoon drive(15-19), 5=Evening(19-00)
        pct_homes:
          type: number
          minimum: 0
          maximum: 1
          description: Fraction of visits from this geography.

    PlacecastSelectRequest:
      type: object
      x-motionworks-status: production
      x-motionworks-source: placecast-select
      x-motionworks-source-doc: https://docs.mworks.com/docs/placecast-select
      required: [name, place_ids, start_datetime, end_datetime]
      properties:
        name:
          type: string
        place_ids:
          type: array
          minItems: 1
          items:
            type: integer
          description: One or more Motionworks place IDs.
        start_datetime:
          type: string
          description: ISO 8601 in the place's local timezone.
        end_datetime:
          type: string
        segment_ids:
          type: array
          items:
            type: string
          description: Optional Motionworks segment IDs to force inclusion.
        custom_dwell_threshold:
          type: number
          minimum: 2
          maximum: 30
          description: Custom dwell threshold in minutes. Defaults to the place's native threshold.

    PlacecastSelection:
      type: object
      properties:
        selection_id:
          type: string
        name:
          type: string
        status:
          type: string
          enum: [pending, processing, complete, failed]
        place_ids:
          type: array
          items:
            type: integer
        start_datetime:
          type: string
        end_datetime:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        # Result fields (populated when status=complete)
        activities:
          type: integer
          nullable: true
        visits:
          type: integer
          nullable: true
        dropoffs:
          type: integer
          nullable: true
        passbys:
          type: integer
          nullable: true
        stays:
          type: integer
          nullable: true
        visits_ci:
          $ref: '#/components/schemas/VisitsCi'
          nullable: true
        visits_observations:
          type: integer
          nullable: true
        imputed:
          type: boolean
          nullable: true
        visits_avg_dwell:
          type: number
          nullable: true
        visits_unique_persons:
          type: integer
          nullable: true
        error:
          type: string
          nullable: true

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

    Provenance:
      type: object
      properties:
        source:
          type: string
        source_doc:
          type: string
          format: uri
        methodology_version:
          type: string
        data_vintage:
          type: string
          format: date
        data_freshness:
          type: string
        data_latency_days:
          type: integer
        data_maturity:
          type: string
          enum: [production, research-preview, synthetic-only, roadmap]
        is_focused:
          type: boolean

    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
            docs_url:
              type: string

paths:
  # ─── Placecast Profiles (weekly rolling) ─────────────────────────────

  /placecast/profiles/{place_id}:
    get:
      operationId: getPlacecastProfile
      summary: Weekly rolling visit profile for a place
      description: >
        Returns the 6-week rolling average published_date report for a place.
        visits is weekly, not daily. visits_ci is a 90% CI.
        Use `published_date` param to retrieve a specific week's publication.
      x-credit-cost: 2
      x-motionworks-status: production
      x-motionworks-source-doc: https://docs.mworks.com/docs/placecast-profiles
      parameters:
        - name: place_id
          in: path
          required: true
          schema:
            type: integer
        - name: published_date
          in: query
          schema:
            type: string
            format: date
          description: Defaults to the most recent Monday publication.
      responses:
        '200':
          description: Placecast Profile
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/PlacecastProfile'
                  meta:
                    $ref: '#/components/schemas/Meta'
        '404':
          description: Place not found

  /placecast/profiles:
    get:
      operationId: searchPlacecastProfiles
      summary: Search places by visit volume / type / geography
      x-credit-cost: 10
      x-motionworks-status: production
      parameters:
        - name: brand
          in: query
          schema:
            type: string
        - name: place_type
          in: query
          schema:
            type: string
        - name: city
          in: query
          schema:
            type: string
        - name: state
          in: query
          schema:
            type: string
        - name: bbox
          in: query
          schema:
            type: string
        - name: min_visits
          in: query
          schema:
            type: integer
        - name: published_date
          in: query
          schema:
            type: string
            format: date
        - name: cursor
          in: query
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
      responses:
        '200':
          description: Paginated PlacecastProfiles
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PlacecastProfile'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
                  meta:
                    $ref: '#/components/schemas/Meta'

  # ─── Placecast By Date (hourly) ───────────────────────────────────────

  /placecast/by-date/{place_id}:
    get:
      operationId: getPlacecastByDate
      summary: Hourly visits + occupancy for a place
      description: >
        Returns hourly visit and occupancy data for the average week of the
        specified month. Omit day_type or hour to return all values for that
        axis. Note: visits_avg_dwell is in HOURS (not minutes) in this product.
      x-credit-cost: 5
      x-motionworks-status: production
      x-motionworks-source-doc: https://docs.mworks.com/docs/placecast-by-date
      parameters:
        - name: place_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 PlacecastByDate rows matching the filter
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PlacecastByDate'
                  meta:
                    $ref: '#/components/schemas/Meta'

  # ─── Placecast Trade Areas ────────────────────────────────────────────

  /placecast/trade-areas/{place_id}:
    get:
      operationId: getPlacecastTradeAreas
      summary: Home-geography distribution of visitors
      description: >
        Returns the distribution of where visitors live (pct_homes per
        geography per month × day_type × day_part). Regional geographies
        (county-level) sum to 100% of visits; neighbourhood geographies
        (<50 miles) are partial and sum to <100%.
      x-credit-cost: 10
      x-motionworks-status: production
      x-motionworks-source-doc: https://docs.mworks.com/docs/placecast-trade-areas
      parameters:
        - name: place_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: day_part
          in: query
          schema:
            type: integer
            enum: [1, 2, 3, 4, 5]
        - name: cursor
          in: query
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 1000
            default: 100
      responses:
        '200':
          description: Paginated PlacecastTradeArea rows
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PlacecastTradeArea'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
                  meta:
                    $ref: '#/components/schemas/Meta'

  # ─── Placecast Select (on-demand scenarios) ───────────────────────────

  /placecast/select:
    post:
      operationId: createPlacecastSelection
      summary: Create an on-demand visit analysis for specific date-time windows
      x-credit-cost: 25
      x-motionworks-status: production
      x-motionworks-source-doc: https://docs.mworks.com/docs/placecast-select
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlacecastSelectRequest'
      responses:
        '202':
          description: Selection accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/PlacecastSelection'
                  meta:
                    $ref: '#/components/schemas/Meta'

    get:
      operationId: listPlacecastSelections
      summary: List Placecast Select scenarios
      x-credit-cost: 5
      x-motionworks-status: production
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [pending, processing, complete, failed]
        - name: cursor
          in: query
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
      responses:
        '200':
          description: Paginated selections
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/PlacecastSelection'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
                  meta:
                    $ref: '#/components/schemas/Meta'

  /placecast/select/{selection_id}:
    get:
      operationId: getPlacecastSelection
      summary: Get selection detail and results (polling endpoint)
      x-credit-cost: 5
      x-motionworks-status: production
      parameters:
        - name: selection_id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Selection with results when complete
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/PlacecastSelection'
                  meta:
                    $ref: '#/components/schemas/Meta'
