openapi: 3.1.0
info:
  title: Set Dynamics
  version: 2.0.0
  description: |
    Set Dynamics measures the reach and frequency of an out-of-home campaign: how many people were exposed to a set of spots, and how often. You describe a **scenario** — the Geopath spots in the campaign, the period (starting on a Monday and ending on a Sunday), the cohort (an audience segment within a geography), which exposure measures to compute (Visits, Circulation, Opportunity to See, Likelihood to See), the durations to report (7, 14, 21 or 28 days) and the effective-frequency thresholds — and Motionworks returns, for each duration, the share of the cohort reached at or above each threshold. Reach estimates carry a 90% confidence interval.

    Analysis is asynchronous. Submitting a scenario returns `202` with `status: "queued"`; poll the scenario until `status` is `complete` (the `result` is populated) or `failed` (the `error` is populated). Results are typically ready within 24–48 hours.

    Authenticate with an org-scoped API key (`X-API-Key: mw_…`). When live, submitting a scenario will cost 25 credits and listing or polling 1 credit each. Prose guides: [Set Dynamics](https://www.mworks.com/docs/set-dynamics/), [Requests](https://www.mworks.com/docs/set-dynamics/set-dynamics/set-dynamics-requests/) and [Responses](https://www.mworks.com/docs/set-dynamics/set-dynamics/set-dynamics-responses/).

    **Availability:** not yet live — Set Dynamics is not yet served by the Motionworks API; calls currently return 404 `NOT_FOUND`.
  contact:
    name: Motionworks AI
    url: https://mworks.com
    email: api@mworks.com
servers:
  - url: https://api2.mworks.com/v2
    description: Production
security:
  - apiKey: []
components:
  securitySchemes:
    apiKey:
      type: apiKey
      name: X-API-Key
      in: header
  schemas:
    SetDynamicsType:
      type: string
      enum:
        - visits_freq_per_period
        - circ_freq_per_period
        - ots_freq_per_period
        - lts_freq_per_period
      description: |
        Which exposure measure to compute. The four exposure measures build on one another: **Visits** (`visits_freq_per_period`) counts presence in the viewshed; **Circulation** (`circ_freq_per_period`) adjusts visits for vehicle occupancy; **Opportunity to See** (`ots_freq_per_period`) adjusts circulation for dwell time and spot duration; **Likelihood to See** (`lts_freq_per_period`) adjusts OTS by the Geopath Visibility Adjustment Index. Likelihood to See is the measure most planners report.
    Duration:
      type: integer
      enum:
        - 7
        - 14
        - 21
        - 28
      description: 'Analysis duration in days: 7, 14, 21 or 28.'
    SetDynamicsPeriod:
      type: object
      required:
        - name
        - start_date
        - end_date
      properties:
        name:
          type: string
          description: Your own label for the period.
        start_date:
          type: string
          format: date
          description: |
            First day of the analysis period (`YYYY-MM-DD`). Periods start on a Monday; a mid-week date may be moved back to the preceding Monday.
        end_date:
          type: string
          format: date
          description: |
            Last day of the analysis period (`YYYY-MM-DD`). Periods end on a Sunday; a mid-week date may be moved forward to the following Sunday.
      description: The analysis period. Periods start on a Monday and end on a Sunday.
    SetDynamicsCustomer:
      type: object
      required:
        - customer_id
        - customer_name
        - customer_scenario_id
        - customer_scenario_name
      properties:
        customer_id:
          type: integer
          description: Your Motionworks customer id.
        customer_name:
          type: string
          description: Your organization's name.
        customer_scenario_id:
          type: string
          description: Your own id for this scenario, for tracking it in your systems.
        customer_scenario_name:
          type: string
          description: Your own human-readable name for this scenario.
        customer_scenario_info:
          type: string
          description: |
            Free-form notes about the scenario — for example who requested it — stored as a string and echoed back unchanged.
      description: Who the scenario is for and how you identify it. Echoed back unchanged in the result.
    SetDynamicsCohort:
      type: object
      required:
        - customer_segment_id
        - customer_base_segment_id
        - geography_ids
        - measuresRelease
      properties:
        customer_segment_id:
          type: integer
          description: Id of the audience segment to measure (the target demographic).
        customer_base_segment_id:
          type: integer
          description: |
            Id of the base segment the target is measured against (for example a broad age group such as Persons 18+).
        geography_ids:
          type: array
          minItems: 1
          items:
            type: string
          description: |
            Geography ids for the analysis: `["GLOBAL"]` for national, a single DMA such as `["US2020XDMA532"]`, or a list of counties such as `["US2020STCO36061", "US2020STCO34003"]`.
        measuresRelease:
          type: integer
          description: |
            The measures release the analysis should use, as a version number (for example `20250501`), so results stay consistent across scenarios.
      description: |
        The audience to measure: a target segment, the base segment it is measured against, and the geography.
    SetDynamicsRequest:
      type: object
      x-motionworks-status: production
      x-motionworks-source: set-dynamics
      x-motionworks-source-doc: https://docs.mworks.com/docs/set-dynamics-requests
      required:
        - scenarioId
        - name
        - periods
        - customer
        - cohort
        - geopath_spot_list
      properties:
        scenarioId:
          type: string
          description: Scenario identifier.
        name:
          type: string
          description: Your name for the scenario.
        description:
          type: string
          description: Optional description of the scenario.
        periods:
          $ref: '#/components/schemas/SetDynamicsPeriod'
        customer:
          $ref: '#/components/schemas/SetDynamicsCustomer'
        type_list:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/SetDynamicsType'
          default:
            - visits_freq_per_period
          description: |
            Exposure measures to compute. Defaults to Visits (`visits_freq_per_period`) when omitted; request several to receive several reach series.
        cohort:
          $ref: '#/components/schemas/SetDynamicsCohort'
        effective_freq_list:
          type: array
          minItems: 1
          items:
            type: integer
            minimum: 1
          default:
            - 1
            - 2
            - 3
            - 4
            - 5
            - 6
            - 7
            - 8
            - 9
            - 10
            - 11
            - 20
            - 50
            - 100
          description: |
            Effective-frequency thresholds to report reach at (minimum exposures per person). Defaults to 1–11, 20, 50 and 100.
        duration_list:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/Duration'
          default:
            - 28
          description: Durations to report, in days (7, 14, 21 or 28; each must fit inside the period). Defaults to 28.
        geopath_spot_list:
          type: array
          minItems: 1
          items:
            type: string
          description: The Geopath spot ids in the campaign. At least one.
      description: 'A scenario to analyze: the spots, period, cohort, measures, durations and frequency thresholds.'
    SetDynamicsFrequencyResult:
      type: object
      required:
        - effective_freq
      properties:
        effective_freq:
          type: string
          description: |
            The frequency threshold (minimum number of exposures), as a string — for example `"3"` means reached three or more times.
        lts_reach:
          type: number
          minimum: 0
          maximum: 1
          description: Likelihood-to-See reach at this threshold, as a share of the cohort (`0.38148` = 38.148%).
        ots_reach:
          type: number
          minimum: 0
          maximum: 1
          description: Opportunity-to-See reach at this threshold, as a share of the cohort.
        circ_reach:
          type: number
          minimum: 0
          maximum: 1
          description: Circulation reach at this threshold, as a share of the cohort.
        visits_reach:
          type: number
          minimum: 0
          maximum: 1
          description: Visits reach at this threshold, as a share of the cohort.
      description: |
        Reach at one effective-frequency threshold: the share of the cohort exposed at least this many times. One reach field is present per requested measure.
    SetDynamicsDurationResult:
      type: object
      required:
        - duration
        - effective_freq_list
      properties:
        duration:
          type: string
          description: The duration in days these results cover, as a string (for example `"28"`).
        effective_freq_list:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/SetDynamicsFrequencyResult'
          description: Reach at each requested effective-frequency threshold.
      description: The reach curve for one requested duration.
    SetDynamicsResponse:
      type: object
      x-motionworks-status: production
      x-motionworks-source: set-dynamics
      x-motionworks-source-doc: https://docs.mworks.com/docs/set-dynamics-responses
      required:
        - customer
        - cohort
        - effective_reach_per_duration
        - messages
      properties:
        customer:
          $ref: '#/components/schemas/SetDynamicsCustomer'
        cohort:
          $ref: '#/components/schemas/SetDynamicsCohort'
        effective_reach_per_duration:
          type: array
          items:
            $ref: '#/components/schemas/SetDynamicsDurationResult'
          description: One entry per requested duration, each with reach at every effective-frequency threshold.
        messages:
          type: string
          description: Status message from the analysis (`Success` when everything ran cleanly).
      description: |
        The completed analysis: your customer and cohort details echoed back, and a reach curve for each requested duration.
    SetDynamicsScenario:
      type: object
      description: |
        A scenario as the API tracks it: what you submitted, its current status, timestamps, and — once complete — the result.
      properties:
        scenarioId:
          type: string
          description: The scenario's id. Use it to poll `GET /set-dynamics/scenarios/{scenario_id}`.
        name:
          type: string
          description: Your name for the scenario.
        description:
          type: string
          description: Your description of the scenario, if you gave one.
        status:
          type: string
          enum:
            - queued
            - processing
            - complete
            - failed
          description: |
            Where the analysis is: `queued` (accepted, not started), `processing`, `complete` (`result` is populated) or `failed` (`error` is populated).
        periods:
          $ref: '#/components/schemas/SetDynamicsPeriod'
        customer:
          $ref: '#/components/schemas/SetDynamicsCustomer'
        type_list:
          type: array
          items:
            $ref: '#/components/schemas/SetDynamicsType'
          description: The exposure measures being computed.
        cohort:
          $ref: '#/components/schemas/SetDynamicsCohort'
        effective_freq_list:
          type: array
          items:
            type: integer
          description: The effective-frequency thresholds being reported.
        duration_list:
          type: array
          items:
            $ref: '#/components/schemas/Duration'
          description: The durations being reported, in days.
        geopath_spot_list:
          type: array
          items:
            type: string
          description: The Geopath spot ids in the scenario.
        created_at:
          type: string
          format: date-time
          description: When the scenario was submitted (ISO 8601).
        updated_at:
          type: string
          format: date-time
          description: When the scenario last changed state (ISO 8601).
        completed_at:
          type: string
          format: date-time
          nullable: true
          description: When the analysis finished (ISO 8601), or `null` while it is still running.
        result:
          oneOf:
            - $ref: '#/components/schemas/SetDynamicsResponse'
            - type: 'null'
          description: The analysis result once `status` is `complete`; `null` before then.
        error:
          type: string
          nullable: true
          description: Why the analysis failed, when `status` is `failed`; otherwise `null`.
    Pagination:
      type: object
      properties:
        cursor:
          type: string
          nullable: true
          description: Opaque cursor for the next page. Pass it back as `cursor` to continue; absent on the last page.
        has_more:
          type: boolean
          description: Whether another page follows.
        total:
          type: integer
          description: Total matching results, when the endpoint reports one.
    Provenance:
      type: object
      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
          description: The Motionworks dataset or model the result came from.
        source_doc:
          type: string
          format: uri
          description: Link to the methodology or dataset documentation for this result.
        methodology_version:
          type: string
          description: Version of the methodology that produced the result.
        data_vintage:
          type: string
          format: date
          description: The date the underlying data represents.
        data_freshness:
          type: string
          enum:
            - hourly
            - daily
            - weekly
            - monthly
            - annually
            - on-demand
            - static
          description: How often the underlying data is refreshed (for example `daily`, `monthly`, `annually`).
        data_latency_days:
          type: integer
          description: Typical days between an observation and its availability in the API.
        data_maturity:
          type: string
          enum:
            - production
            - research-preview
            - synthetic-only
            - roadmap
          description: |
            Maturity of the data behind the result: `production` (supported and stable), `research-preview` (available, subject to change), or a pre-release value (`roadmap`, or generated placeholder data not yet backed by production measurement).
        is_focused:
          type: boolean
          description: |
            Whether the place is directly measured (`true`) rather than estimated from its peer group (`false`). When present alongside `measurement_method`, the two agree.
        measurement_method:
          type: string
          enum:
            - direct
            - estimated
          description: |
            `direct` when the place is measured directly; `estimated` when its statistics come from peer-group inference. When present alongside `is_focused`, the two agree (`true` ↔ `direct`).
    Meta:
      type: object
      properties:
        request_id:
          type: string
          description: Unique id for this request. Quote it when contacting support.
        credits_used:
          type: integer
          description: Credits charged for this call.
        credits_remaining:
          type: integer
          description: Credits remaining on your account after this call.
        product:
          type: string
          description: The Motionworks product that served the call.
        version:
          type: string
          description: API version that served the call.
        provenance:
          $ref: '#/components/schemas/Provenance'
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: Stable machine-readable error code.
            message:
              type: string
              description: Human-readable explanation of the error.
            status:
              type: integer
              description: HTTP status code, repeated in the body.
            request_id:
              type: string
              description: Unique id for this request. Quote it when contacting support.
            product:
              type: string
              description: The Motionworks product that produced the error.
            docs_url:
              type: string
              description: Link to the documentation for this error code.
          description: 'The error: a stable `code`, a human-readable `message`, and the HTTP `status`.'
paths:
  /set-dynamics/scenarios:
    post:
      operationId: createSetDynamicsScenario
      summary: Submit a scenario
      description: |
        Queues a reach-and-frequency analysis for the scenario you describe. The response is the queued scenario with `status: "queued"`; poll `GET /set-dynamics/scenarios/{scenario_id}` until `status` is `complete` or `failed`. Results are typically ready within 24–48 hours. Authenticate with an org-scoped API key (`X-API-Key: mw_…`). 25 credits per submission when live.

        Rules that matter: the period starts on a Monday and ends on a Sunday; every duration must be 7, 14, 21 or 28 days and fit inside the period; `geopath_spot_list` needs at least one spot. When omitted, `type_list` defaults to Visits, `duration_list` to 28 days, and `effective_freq_list` to 1–11, 20, 50 and 100.

        **Availability:** not yet live — Set Dynamics is not yet served by the Motionworks API; calls currently return 404 `NOT_FOUND`.
      tags:
        - Scenarios
      x-credit-cost: 25
      x-motionworks-status: production
      x-motionworks-source-doc: https://docs.mworks.com/docs/set-dynamics-requests
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetDynamicsRequest'
      responses:
        '202':
          description: 'Scenario accepted and queued. The body is the scenario with `status: "queued"` and no `result` yet.'
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/SetDynamicsScenario'
                  meta:
                    $ref: '#/components/schemas/Meta'
        '400':
          description: |
            Invalid scenario — for example a start date that is not a Monday, an end date that is not a Sunday, a duration outside 7/14/21/28 or longer than the period, an empty spot list, or an unrecognized geography id.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    get:
      operationId: listSetDynamicsScenarios
      summary: List scenarios
      tags:
        - Scenarios
      description: |
        Returns your organization's scenarios, newest first, with cursor pagination. Filter by `status` or by your own `customer_scenario_id`. Authenticate with an org-scoped API key (`X-API-Key: mw_…`). 1 credit per call when live.

        **Availability:** not yet live — Set Dynamics is not yet served by the Motionworks API; calls currently return 404 `NOT_FOUND`.
      x-credit-cost: 1
      x-motionworks-status: production
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum:
              - queued
              - processing
              - complete
              - failed
          description: Return only scenarios in this state.
        - name: customer_scenario_id
          in: query
          schema:
            type: string
          description: Return only the scenario you submitted with this `customer.customer_scenario_id`.
        - name: cursor
          in: query
          schema:
            type: string
          description: Cursor from the previous page's `pagination.cursor`.
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          description: Scenarios per page (1–100, default 25).
      responses:
        '200':
          description: A page of scenarios.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/SetDynamicsScenario'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
                  meta:
                    $ref: '#/components/schemas/Meta'
  /set-dynamics/scenarios/{scenario_id}:
    get:
      operationId: getSetDynamicsScenario
      summary: Read a scenario
      tags:
        - Scenarios
      description: |
        Returns one scenario by id, including its current `status`. This is the polling endpoint: once `status` is `complete`, `result` carries the reach at each effective-frequency threshold for each duration; if it is `failed`, `error` says why. Authenticate with an org-scoped API key (`X-API-Key: mw_…`). 1 credit per call when live.

        **Availability:** not yet live — Set Dynamics is not yet served by the Motionworks API; calls currently return 404 `NOT_FOUND`.
      x-credit-cost: 1
      x-motionworks-status: production
      x-motionworks-source-doc: https://docs.mworks.com/docs/set-dynamics-responses
      parameters:
        - name: scenario_id
          in: path
          required: true
          schema:
            type: string
          description: The scenario's `scenarioId` from the submit or list response.
      responses:
        '200':
          description: The scenario, with `result` populated when `status` is `complete`.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/SetDynamicsScenario'
                  meta:
                    $ref: '#/components/schemas/Meta'
        '404':
          description: Unknown `scenario_id`, or a scenario that does not belong to your organization.
x-tagGroups:
  - name: Set Dynamics
    tags:
      - Scenarios
tags:
  - name: Scenarios
    description: |
      Submit a reach-and-frequency scenario, list your scenarios, and poll one until its result is ready. When live: 25 credits to submit, 1 credit to list or poll. Not yet live — calls currently return 404 `NOT_FOUND`.
x-customer-voice: true
