{
  "openapi": "3.0.4",
  "info": {
    "title": "Revel Digital REST API",
    "description": "Provides REST based access to your Revel Digital account",
    "version": "v1"
  },
  "servers": [
    {
      "url": "https://api.reveldigital.com"
    }
  ],
  "paths": {
    "/account": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Gets account details.",
        "description": "",
        "operationId": "GetAccount",
        "responses": {
          "200": {
            "description": "Returns account details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "400": {
            "description": "If the account API key is invalid"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Account"
        ],
        "summary": "Updates an account.",
        "description": "",
        "operationId": "PutAccount",
        "requestBody": {
          "description": "Account",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Account"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "If the account API key is invalid"
          },
          "201": {
            "description": "If account was updated successfully"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/account/organizations": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Gets organizations.",
        "description": "",
        "operationId": "GetOrganizations",
        "responses": {
          "200": {
            "description": "Returns list of organizations",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Organization"
                  }
                }
              }
            }
          },
          "400": {
            "description": "If the account API key is invalid"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/account/auditevents": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Gets audit events for the account.",
        "description": "\r\n<b>Authorization:</b> This endpoint requires the user to be an account owner.",
        "operationId": "GetAuditEvents",
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "description": "Filter by user ID (encrypted)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "eventType",
            "in": "query",
            "description": "Filter by event type",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "httpMethod",
            "in": "query",
            "description": "Filter by HTTP method (GET, POST, PUT, DELETE, etc.)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "controllerName",
            "in": "query",
            "description": "Filter by controller name",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "actionName",
            "in": "query",
            "description": "Filter by action name",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Filter events after this date (ISO 8601 format)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Filter events before this date (ISO 8601 format)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "ipAddress",
            "in": "query",
            "description": "Filter by IP address",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "responseCode",
            "in": "query",
            "description": "Filter by HTTP response code",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of items to return (default: 100)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 100
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number for pagination (0-based)",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns list of audit events",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AuditEvent"
                  },
                  "description": "Collection of audit events"
                }
              }
            }
          },
          "403": {
            "description": "If the user is not an account owner"
          },
          "400": {
            "description": "If the account API key is invalid"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/account/auditevents/{eventId}": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Gets a single audit event by ID.",
        "description": "\r\n<b>Authorization:</b> This endpoint requires the user to be an account owner.",
        "operationId": "GetAuditEvent",
        "parameters": [
          {
            "name": "eventId",
            "in": "path",
            "description": "The audit event ID",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns audit event details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditEvent"
                }
              }
            }
          },
          "403": {
            "description": "If the user is not an account owner"
          },
          "404": {
            "description": "If the audit event is not found"
          },
          "400": {
            "description": "If the account API key is invalid"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/dataset": {
      "post": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Returns AdHawk dataset based on the provided post parameters.\r\nThis is a legacy endpoint that returns raw dataset results.\r\nConsider using the newer typed endpoints for better structure.",
        "operationId": "GetAdHawkDataset",
        "requestBody": {
          "description": "Dataset request parameters",
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/AdHawkDatasetPostBody"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdHawkDatasetPostBody"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AdHawkDatasetPostBody"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AdHawkDatasetPostBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/playlogs": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets play logs for the account.",
        "operationId": "GetPlayLogs",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "fileId",
            "in": "query",
            "description": "Optional list of file IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 1000, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkPlayLog"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/pinglogs": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets ping/heartbeat logs for the account.",
        "operationId": "GetPingLogs",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "Optional list of ping types to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int32"
              }
            }
          },
          {
            "name": "minCpuUsage",
            "in": "query",
            "description": "Minimum CPU usage to filter by",
            "schema": {
              "type": "number",
              "format": "float"
            }
          },
          {
            "name": "minMemoryUsage",
            "in": "query",
            "description": "Minimum memory usage to filter by",
            "schema": {
              "type": "number",
              "format": "float"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 1000, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkPingLog"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/eventlogs": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets event logs for the account.",
        "operationId": "GetEventLogs",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "eventName",
            "in": "query",
            "description": "Optional list of event names to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "sessionId",
            "in": "query",
            "description": "Optional session ID to filter by",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 1000, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkEventLog"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/eventmetrics": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets aggregated event metrics for the account.",
        "operationId": "GetEventMetrics",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "eventName",
            "in": "query",
            "description": "Optional list of event names to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "interval",
            "in": "query",
            "description": "Time interval for aggregation (minute, hour, day, week, month)",
            "schema": {
              "$ref": "#/components/schemas/AdHawkIntervalType"
            }
          },
          {
            "name": "groupByDevice",
            "in": "query",
            "description": "Group by device (default: false). When false and groupByEvent is also false, returns totals aggregated only by interval.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "groupByEvent",
            "in": "query",
            "description": "Group by event name (default: false)",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 1000, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkEventMetrics"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/impressions": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets audience impressions for the account.",
        "operationId": "GetImpressions",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "Optional list of impression types to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "integer",
                "format": "int32"
              }
            }
          },
          {
            "name": "gender",
            "in": "query",
            "description": "Optional gender to filter by",
            "schema": {
              "$ref": "#/components/schemas/AdHawkGender"
            }
          },
          {
            "name": "minDwellTime",
            "in": "query",
            "description": "Minimum dwell time in milliseconds",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 1000, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkImpression"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/devicemetrics": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets aggregated device health metrics for the account.",
        "operationId": "GetDeviceMetrics",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "interval",
            "in": "query",
            "description": "Time interval for aggregation (minute, hour, day, week, month)",
            "schema": {
              "$ref": "#/components/schemas/AdHawkIntervalType"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 1000, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkDeviceMetrics"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/audiencemetrics": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets aggregated audience metrics for the account.",
        "operationId": "GetAudienceMetrics",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "interval",
            "in": "query",
            "description": "Time interval for aggregation (minute, hour, day, week, month)",
            "schema": {
              "$ref": "#/components/schemas/AdHawkIntervalType"
            }
          },
          {
            "name": "groupByDevice",
            "in": "query",
            "description": "Group by device (default: false). When false, returns totals aggregated only by interval.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "includeDwellTime",
            "in": "query",
            "description": "Include dwell time data (queries exit events)",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 1000, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkAudienceMetrics"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/mediaplaystats": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets media play statistics aggregated by file.",
        "operationId": "GetMediaPlayStats",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "fileId",
            "in": "query",
            "description": "Optional list of file IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 100, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkMediaPlayStats"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/deviceplaystats": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets device play statistics aggregated by device.",
        "operationId": "GetDevicePlayStats",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "fileId",
            "in": "query",
            "description": "Optional list of file IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 100, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkDevicePlayStats"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/playstatsbytime": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets time-series play statistics aggregated by interval.",
        "operationId": "GetPlayStatsByTime",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "fileId",
            "in": "query",
            "description": "Optional list of file IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "interval",
            "in": "query",
            "description": "Time interval for aggregation (minute, hour, day, week, month)",
            "schema": {
              "$ref": "#/components/schemas/AdHawkIntervalType"
            }
          },
          {
            "name": "groupByDevice",
            "in": "query",
            "description": "Group by device",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "groupByFile",
            "in": "query",
            "description": "Group by file",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 1000, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkPlayStatsByTime"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/eventflow": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets event flow data for Sankey-type visualizations.\r\nBuilds a chronological sequence of events indicating the path users took through sessions.",
        "operationId": "GetEventFlow",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "eventName",
            "in": "query",
            "description": "Optional list of event names to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "eventDepthLevel",
            "in": "query",
            "description": "Maximum depth level for event flow (default: 6)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 6
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 1000, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkEventFlow"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/heatmap": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets geographic heatmap data aggregated by location.\r\nUseful for heatmap or geographic visualizations.",
        "operationId": "GetHeatMapData",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "interval",
            "in": "query",
            "description": "Time interval for aggregation (minute, hour, day, week, month)",
            "schema": {
              "$ref": "#/components/schemas/AdHawkIntervalType"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 1000, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkHeatMapData"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/mediaimpressions": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets media impressions (OTS - Opportunity To See) data aggregated by media file.\r\nJoins audience/impression data with play logs to determine which audience members\r\nhad an opportunity to see specific media content during playback.",
        "operationId": "GetMediaImpressions",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "fileId",
            "in": "query",
            "description": "Optional list of file/media IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "minDwellThreshold",
            "in": "query",
            "description": "Minimum dwell time in milliseconds to count as \"viewed\" (default: 100ms)",
            "schema": {
              "type": "integer",
              "format": "int64",
              "default": 100
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 100, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkMediaImpressions"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/adhawk/devicemediaimpressions": {
      "get": {
        "tags": [
          "AdHawk"
        ],
        "summary": "Gets media impressions (OTS - Opportunity To See) data aggregated by device.\r\nJoins audience/impression data with play logs to determine which devices\r\nhad the most audience engagement during media playback.",
        "operationId": "GetDeviceMediaImpressions",
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "description": "Start date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "End date for the query (required)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "deviceId",
            "in": "query",
            "description": "Optional list of device IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "fileId",
            "in": "query",
            "description": "Optional list of file/media IDs to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "minDwellThreshold",
            "in": "query",
            "description": "Minimum dwell time in milliseconds to count as \"viewed\" (default: 100ms)",
            "schema": {
              "type": "integer",
              "format": "int64",
              "default": 100
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of results (default: 100, max: 10000)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AdHawkDeviceMediaImpressions"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/alerts": {
      "get": {
        "tags": [
          "Alerts"
        ],
        "summary": "Gets all alerts for the account.",
        "operationId": "GetAlerts",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Unique identifier for the alert (encrypted)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "device_id",
            "in": "query",
            "description": "Filter by device IDs (encrypted)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "active_only",
            "in": "query",
            "description": "Filter to show only active alerts (not resolved and not snoozed)",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "resolved",
            "in": "query",
            "description": "Filter by resolved state",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "org_id",
            "in": "query",
            "description": "Filter by organization ID (encrypted)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "in": "query",
            "description": "Maximum number of items to retrieve",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number for pagination",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Alert"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/alerts/{id}": {
      "get": {
        "tags": [
          "Alerts"
        ],
        "summary": "Gets an alert by ID.",
        "operationId": "GetAlertById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Alert ID (encrypted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Alert"
                }
              }
            }
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Alerts"
        ],
        "summary": "Updates an alert (snooze or resolve).",
        "operationId": "PutAlert",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Alert ID (encrypted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Alert update request",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AlertRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Alert"
                }
              }
            }
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "patch": {
        "tags": [
          "Alerts"
        ],
        "summary": "Partially updates an alert using JSON Patch.\r\nUses the JSON Patch syntax (http://jsonpatch.com)",
        "operationId": "PatchAlert",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Alert ID (encrypted)",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Patch document",
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/JsonPatchDocument"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Alert"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/alerts/rules": {
      "get": {
        "tags": [
          "Alerts"
        ],
        "summary": "Gets all alert rules for the authenticated account.",
        "description": "An alert rule defines the conditions that raise alerts for one or more devices.\r\nResults are scoped to the account associated with the API key and can be narrowed,\r\npaginated, and filtered using the query parameters below.\r\nRequires the `AlertRules_View` securable.",
        "operationId": "GetAlertRules",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Optional single alert rule ID to filter by.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "org_id",
            "in": "query",
            "description": "Optional organization ID to filter by.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "in": "query",
            "description": "Optional maximum number of rules to return (page size). Omit for the server default.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Optional 1-based page number, used together with take for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The list of alert rules (may be empty).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AlertRule"
                  }
                }
              }
            }
          },
          "401": {
            "description": "The API key is missing or invalid."
          },
          "403": {
            "description": "The caller lacks the AlertRules_View securable."
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Alerts"
        ],
        "summary": "Creates a new alert rule.",
        "description": "Creates an alert rule for the authenticated account and returns the created resource,\r\nincluding its newly assigned ID, with a `Location` header pointing at\r\nthe `GetAlertRuleById` route.\r\n            \r\nThe `rule_set` field, when provided, must be a JSON string describing the trigger\r\nconditions. Its schema and validation rules are documented on\r\nRevelDigital.Core.PublicApi.Models.AlertRuleRequest.RuleSet. Invalid rule sets are rejected with 400.\r\nRequires the `AlertRules_Edit` securable.",
        "operationId": "CreateAlertRule",
        "requestBody": {
          "description": "The alert rule to create. See RevelDigital.Core.PublicApi.Models.AlertRuleRequest for field semantics.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AlertRuleRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The alert rule was created; the body contains the created rule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertRule"
                }
              }
            }
          },
          "400": {
            "description": "The request body is invalid (for example, a malformed or semantically invalid rule_set)."
          },
          "401": {
            "description": "The API key is missing or invalid."
          },
          "403": {
            "description": "The caller lacks the AlertRules_Edit securable."
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/alerts/rules/{id}": {
      "get": {
        "tags": [
          "Alerts"
        ],
        "summary": "Gets a single alert rule by its ID.",
        "description": "Returns the full alert rule, including its rule set, device/user associations,\r\nand audit timestamps. The rule must belong to the authenticated account.\r\nRequires the `AlertRules_View` securable.",
        "operationId": "GetAlertRuleById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The alert rule ID.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The requested alert rule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertRule"
                }
              }
            }
          },
          "404": {
            "description": "No alert rule with the given ID exists for this account."
          },
          "401": {
            "description": "The API key is missing or invalid."
          },
          "403": {
            "description": "The caller lacks the AlertRules_View securable."
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Alerts"
        ],
        "summary": "Updates an existing alert rule.",
        "description": "Replaces the mutable fields of an existing alert rule with the supplied values and\r\nreturns the updated resource. The rule must belong to the authenticated account.\r\n            \r\nThe `rule_set` field, when provided, must be a valid JSON rule set as documented\r\non RevelDigital.Core.PublicApi.Models.AlertRuleRequest.RuleSet; invalid rule sets are rejected with 400.\r\nRequires the `AlertRules_Edit` securable.",
        "operationId": "PutAlertRule",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The alert rule ID to update.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "The updated alert rule values. See RevelDigital.Core.PublicApi.Models.AlertRuleRequest for field semantics.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AlertRuleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The alert rule was updated; the body contains the updated rule.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertRule"
                }
              }
            }
          },
          "404": {
            "description": "No alert rule with the given ID exists for this account."
          },
          "400": {
            "description": "The request body is invalid (for example, a malformed or semantically invalid rule_set)."
          },
          "401": {
            "description": "The API key is missing or invalid."
          },
          "403": {
            "description": "The caller lacks the AlertRules_Edit securable."
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Alerts"
        ],
        "summary": "Deletes an alert rule.",
        "description": "Permanently deletes the alert rule and its device/user associations. This operation\r\nis idempotent from the caller's perspective: deleting a non-existent rule returns 404.\r\nThe rule must belong to the authenticated account.\r\nRequires the `AlertRules_Delete` securable.",
        "operationId": "DeleteAlertRule",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The alert rule ID to delete.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The alert rule was deleted."
          },
          "404": {
            "description": "No alert rule with the given ID exists for this account."
          },
          "401": {
            "description": "The API key is missing or invalid."
          },
          "403": {
            "description": "The caller lacks the AlertRules_Delete securable."
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/datatables": {
      "get": {
        "tags": [
          "DataTables"
        ],
        "summary": "Lists data tables in the account.",
        "operationId": "GetDataTables",
        "parameters": [
          {
            "name": "groupId",
            "in": "query",
            "description": "Optional group ID; when set, only tables belonging to that group are returned.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Maximum number of tables to return per page (default 50).",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          },
          {
            "name": "continuationToken",
            "in": "query",
            "description": "Opaque token from a prior response used to fetch the next page. Omit for the first page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataTableListResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "DataTables"
        ],
        "summary": "Creates a new data table.",
        "operationId": "CreateDataTable",
        "requestBody": {
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDataTableRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDataTableRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDataTableRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDataTableRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataTableDetail"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/datatables/{tableId}": {
      "get": {
        "tags": [
          "DataTables"
        ],
        "summary": "Gets a data table definition by ID.",
        "operationId": "GetDataTable",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataTableDetail"
                }
              }
            }
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "DataTables"
        ],
        "summary": "Updates a data table definition.",
        "operationId": "UpdateDataTable",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDataTableRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDataTableRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDataTableRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDataTableRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataTableDetail"
                }
              }
            }
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "DataTables"
        ],
        "summary": "Deletes a data table and all its rows.",
        "operationId": "DeleteDataTable",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/datatables/{tableId}/rows": {
      "get": {
        "tags": [
          "DataTables"
        ],
        "summary": "Lists rows in a data table with optional filtering, sorting, and pagination.",
        "operationId": "GetDataTableRows",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "description": "The data table ID.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "description": "Optional JSON filter. Equality shortcut `{\"col\":\"value\"}` or operator form\r\n`{\"col\":{\"op\":\"gte\",\"value\":25}}`. Operators: eq, neq, contains, notContains, gt, gte,\r\nlt, lte, inRange, outOfRange, in, notIn, isEmpty, isNotEmpty, positive, negative, beforeNow,\r\nafterNow, isToday. Use a top-level `$or` array for disjunction.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Optional column key to sort by.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sortDir",
            "in": "query",
            "description": "Sort direction: `asc` (default) or `desc`.",
            "schema": {
              "type": "string",
              "default": "asc"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Maximum number of rows to return per page (default 50).",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 50
            }
          },
          {
            "name": "continuationToken",
            "in": "query",
            "description": "Opaque token from a prior response used to fetch the next page. Omit for the first page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Optional comma-separated list of column keys to return; omit to return all columns.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timeZone",
            "in": "query",
            "description": "Optional Windows or IANA time zone id used to evaluate the relative date operators (`isToday`, `beforeNow`, `afterNow`). Defaults to the account's time zone.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RowListResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "DataTables"
        ],
        "summary": "Creates a new row in a data table.",
        "operationId": "CreateDataTableRow",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRowRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRowRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRowRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRowRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataTableRowModel"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/datatables/{tableId}/rows/{rowId}": {
      "get": {
        "tags": [
          "DataTables"
        ],
        "summary": "Gets a single row by ID.",
        "operationId": "GetDataTableRow",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "rowId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataTableRowModel"
                }
              }
            }
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "DataTables"
        ],
        "summary": "Updates a row (partial update).",
        "operationId": "UpdateDataTableRow",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "description": "The data table ID.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "rowId",
            "in": "path",
            "description": "The row ID.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "description": "Optional optimistic-concurrency token. Supply the `ETag` value returned by a\r\nprior read as the `If-Match` header; the update is rejected with\r\n`409 Conflict` if the row changed in the meantime. Omit to update unconditionally.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "The partial row data to merge.",
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRowRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRowRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRowRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRowRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataTableRowModel"
                }
              }
            }
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "DataTables"
        ],
        "summary": "Deletes a row.",
        "operationId": "DeleteDataTableRow",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "rowId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/datatables/{tableId}/rows/batch": {
      "post": {
        "tags": [
          "DataTables"
        ],
        "summary": "Batch creates rows in a data table.",
        "operationId": "BatchCreateDataTableRows",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/BatchCreateRowsRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchCreateRowsRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchCreateRowsRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/BatchCreateRowsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchCreateRowsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/datatables/{tableId}/rows/reorder": {
      "put": {
        "tags": [
          "DataTables"
        ],
        "summary": "Reorders rows in a data table.",
        "operationId": "ReorderDataTableRows",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/ReorderRowsRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReorderRowsRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ReorderRowsRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ReorderRowsRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/datatables/{tableId}/rows/import": {
      "post": {
        "tags": [
          "DataTables"
        ],
        "summary": "Imports rows from a CSV or Excel (.xlsx) file.",
        "operationId": "ImportDataTableRows",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "description": "The data table ID to import into.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "description": "The CSV or Excel (.xlsx/.xls) file to import. The header row must match the table's column\r\nkeys or names (case-insensitive); unmatched columns are ignored.",
                    "format": "binary"
                  },
                  "mode": {
                    "type": "string",
                    "description": "How imported rows are applied: `append` (default) adds them after existing rows;\r\n`replace` deletes all existing rows first, then imports.",
                    "default": "append"
                  }
                }
              },
              "encoding": {
                "file": {
                  "style": "form"
                },
                "mode": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportRowsResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/datatables/{tableId}/rows/export": {
      "get": {
        "tags": [
          "DataTables"
        ],
        "summary": "Exports rows as CSV.",
        "operationId": "ExportDataTableRows",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/datatables/{tableId}/rows/batch-delete": {
      "post": {
        "tags": [
          "DataTables"
        ],
        "summary": "Deletes multiple rows in a single request. Max 100 row IDs per call.",
        "operationId": "BatchDeleteDataTableRows",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/BatchDeleteRowsRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchDeleteRowsRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchDeleteRowsRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/BatchDeleteRowsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchDeleteRowsResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/datatables/{tableId}/rows/{rowId}/versions": {
      "get": {
        "tags": [
          "DataTables"
        ],
        "summary": "Lists version history for a row (newest first).",
        "operationId": "GetRowVersions",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "description": "The data table ID.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "rowId",
            "in": "path",
            "description": "The row ID whose version history is returned.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "Maximum number of versions to return per page (default 25).",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 25
            }
          },
          {
            "name": "continuationToken",
            "in": "query",
            "description": "Opaque token from a prior response used to fetch the next page. Omit for the first page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersionListResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/datatables/{tableId}/rows/{rowId}/versions/{version}": {
      "get": {
        "tags": [
          "DataTables"
        ],
        "summary": "Gets a specific version snapshot of a row.",
        "operationId": "GetRowVersion",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "rowId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RowVersionModel"
                }
              }
            }
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/datatables/{tableId}/rows/{rowId}/rollback": {
      "post": {
        "tags": [
          "DataTables"
        ],
        "summary": "Rolls back a row to a specific version.",
        "operationId": "RollbackRow",
        "parameters": [
          {
            "name": "tableId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "rowId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/RollbackRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RollbackRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/RollbackRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/RollbackRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RollbackResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/devices": {
      "get": {
        "tags": [
          "Devices"
        ],
        "summary": "Gets all devices in an account.",
        "operationId": "GetDevices",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Unique identifier for the device.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "in": "query",
            "description": "Maximum number of items to retrieve in a query.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Current page number for paginated results.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "device_type_id",
            "in": "query",
            "description": "Unique identifier for the type of device.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group_id",
            "in": "query",
            "description": "List of unique identifiers for media groups to filter by.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "group_name",
            "in": "query",
            "description": "Collection of group names to filter by.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "include_snap",
            "in": "query",
            "description": "Include the snapshot of the currently playing content. JPG format, base64 encoded.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "org_id",
            "in": "query",
            "description": "Unique identifier for an organization to filter by.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "is_online",
            "in": "query",
            "description": "Filter devices by their online status.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Device"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Devices"
        ],
        "summary": "Registers a new device.",
        "operationId": "PostDevice",
        "parameters": [
          {
            "name": "activation_code",
            "in": "query",
            "description": "Activation code",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Device",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeviceRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/devices/{id}": {
      "get": {
        "tags": [
          "Devices"
        ],
        "summary": "Gets a device by ID.",
        "operationId": "GetDeviceById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Device Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Devices"
        ],
        "summary": "Updates a device.",
        "description": "Notes, the DOOH screen attributes (screen_orientation, is_audio_enabled, is_outdoor)\r\nand location.venue_id are applied exactly as supplied, so omitting one or sending null\r\nclears it back to \"not stated\". The other optional fields keep their existing value\r\nwhen omitted.\r\n            \r\nVenue is set through location.venue_id. The legacy \"venue:{id}\" tag is deprecated: it\r\nis no longer read or written, and tagging a device will not change its venue.",
        "operationId": "PutDevice",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Device Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Device",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeviceRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Devices"
        ],
        "summary": "Delete a device.",
        "operationId": "DeleteDevice",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Device Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "patch": {
        "tags": [
          "Devices"
        ],
        "summary": "Patch a device. Patch allows partial updates by targeting specific properties of the device.\r\nUses the JSON Patch syntax (http://jsonpatch.com)",
        "description": "The patch is applied to the device's current state, so properties that are not targeted\r\nkeep their existing values. This includes notes, location.venue_id and the DOOH screen\r\nattributes, which a plain PUT would clear if omitted.",
        "operationId": "PatchDevice",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Device Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Patch document",
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/JsonPatchDocument"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/devices/groups": {
      "get": {
        "tags": [
          "Devices"
        ],
        "summary": "Gets device groups in the account.",
        "operationId": "GetDeviceGroups",
        "parameters": [
          {
            "name": "tree",
            "in": "query",
            "description": "Optional hierarchical data format",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "id",
            "in": "query",
            "description": "Optional group id",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "in": "query",
            "description": "Optional number of items to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Optional number of page to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Group"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Devices"
        ],
        "summary": "Create a new device group.",
        "operationId": "PostDeviceGroup",
        "requestBody": {
          "description": "Device group",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Group"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/devices/groups/{id}": {
      "put": {
        "tags": [
          "Devices"
        ],
        "summary": "Updates a device group.",
        "operationId": "PutDeviceGroup",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Group id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Device group",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Devices"
        ],
        "summary": "Delete a device group.",
        "description": "Group must be empty.",
        "operationId": "DeleteDeviceGroup",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Device group Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/devices/pingdata": {
      "get": {
        "tags": [
          "Devices"
        ],
        "summary": "Gets device ping data by registration key.",
        "operationId": "GetPingData",
        "parameters": [
          {
            "name": "key",
            "in": "query",
            "description": "Registration key",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PingData"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/devices/{registrationKey}/snap": {
      "get": {
        "tags": [
          "Devices"
        ],
        "summary": "Gets current snapshot of the device screen. Image is returned as a JPEG image.",
        "operationId": "GetSnapshot",
        "parameters": [
          {
            "name": "registrationKey",
            "in": "path",
            "description": "Device registration key",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "base64",
            "in": "query",
            "description": "If true, the JPG image will be returned as a base64-encoded string",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/devices/{registrationKey}/pingdata": {
      "get": {
        "tags": [
          "Devices"
        ],
        "summary": "Gets device ping data by registration key.",
        "operationId": "GetDevicePingData",
        "parameters": [
          {
            "name": "registrationKey",
            "in": "path",
            "description": "",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PingData"
                }
              }
            }
          }
        }
      }
    },
    "/devices/commands": {
      "post": {
        "tags": [
          "Devices"
        ],
        "summary": "Sends a collection of commands to devices.",
        "operationId": "PostDevicesCommands",
        "requestBody": {
          "description": "Command set",
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/DeviceCommand"
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/devices/{id}/commands": {
      "post": {
        "tags": [
          "Devices"
        ],
        "summary": "Sends a collection of commands to a specific device.",
        "operationId": "PostDeviceCommands",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Device Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Commands",
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Command"
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/devices/{id}/track": {
      "post": {
        "tags": [
          "Devices"
        ],
        "summary": "Create an event associated with a device.",
        "operationId": "PostEvent",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Device Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Event",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Event"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/media": {
      "get": {
        "tags": [
          "Media"
        ],
        "summary": "Gets all media in an account.",
        "operationId": "GetMedia",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Optional Media Id",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "in": "query",
            "description": "Optional number of items to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Optional number of page to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "group_id",
            "in": "query",
            "description": "Optional media group Id",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "group_name",
            "in": "query",
            "description": "Optional group name to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Media"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Media"
        ],
        "summary": "Uploads new media asset.",
        "description": "POST body must be in multipart/form-data format",
        "operationId": "PostMediaMultipart",
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "description": "The media file",
                    "format": "binary"
                  },
                  "name": {
                    "type": "string",
                    "description": "The media name"
                  },
                  "group_id": {
                    "type": "string",
                    "description": "The group id"
                  },
                  "tags": {
                    "type": "string",
                    "description": "The tags associated with this media"
                  },
                  "advertiser_id": {
                    "type": "string",
                    "description": "The advertiser id. Optional"
                  },
                  "is_shared": {
                    "type": "boolean",
                    "description": "Is this media shared with other accounts"
                  },
                  "start_date": {
                    "type": "string",
                    "description": "The start date for this media",
                    "format": "date-time"
                  },
                  "end_date": {
                    "type": "string",
                    "description": "The end date for this media",
                    "format": "date-time"
                  }
                }
              },
              "encoding": {
                "file": {
                  "style": "form"
                },
                "name": {
                  "style": "form"
                },
                "group_id": {
                  "style": "form"
                },
                "tags": {
                  "style": "form"
                },
                "advertiser_id": {
                  "style": "form"
                },
                "is_shared": {
                  "style": "form"
                },
                "start_date": {
                  "style": "form"
                },
                "end_date": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Media"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/media/{id}": {
      "get": {
        "tags": [
          "Media"
        ],
        "summary": "Gets media item by ID.",
        "operationId": "GetMediaById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Media Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Media"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Media"
        ],
        "summary": "Update media asset properties.",
        "operationId": "PutMedia",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Media Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MediaRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "patch": {
        "tags": [
          "Media"
        ],
        "summary": "Patch a media item. Patch allows partial updates by targeting specific properties of the schedule.\r\nUses the JSON Patch syntax (http://jsonpatch.com)",
        "operationId": "PatchMedia",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Media Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Patch update",
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/JsonPatchDocument"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Media"
        ],
        "summary": "Delete media asset.",
        "operationId": "DeleteMedia",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/media/groups": {
      "get": {
        "tags": [
          "Media"
        ],
        "summary": "Gets media groups.",
        "operationId": "GetMediaGroups",
        "parameters": [
          {
            "name": "tree",
            "in": "query",
            "description": "Optional hierarchical data format",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "id",
            "in": "query",
            "description": "Optional group id",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "in": "query",
            "description": "Optional number of items to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Optional number of page to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Group"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Media"
        ],
        "summary": "Create a new media group.",
        "operationId": "PostMediaGroup",
        "requestBody": {
          "description": "Media group",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Group"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/media/groups/{id}": {
      "put": {
        "tags": [
          "Media"
        ],
        "summary": "Updates a media group.",
        "operationId": "PutMediaGroup",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Group id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Media group",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Media"
        ],
        "summary": "Delete a media group.",
        "description": "Group must be empty.",
        "operationId": "DeleteMediaGroup",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Media group Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/media/{group_id}/{file_name}": {
      "post": {
        "tags": [
          "Media"
        ],
        "summary": "Uploads new media asset.",
        "description": "POST body should contain raw binary media file",
        "parameters": [
          {
            "name": "group_id",
            "in": "path",
            "description": "",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "file_name",
            "in": "path",
            "description": "",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "shared",
            "in": "query",
            "description": "Optional media sharing",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "start_date",
            "in": "query",
            "description": "Optional start date",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "end_date",
            "in": "query",
            "description": "Optional end date",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "advertiser_id",
            "in": "query",
            "description": "Optional advertiser user Id",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "name",
            "in": "query",
            "description": "Optional media name. Overrides the uploaded name",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "description",
            "in": "query",
            "description": "Optional media tags",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Media"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/media/uploads": {
      "post": {
        "tags": [
          "Media"
        ],
        "summary": "Create a presigned direct-to-S3 upload slot.",
        "description": "Returns a short-lived presigned S3 `PUT` URL so a client can upload large binary\r\nartifacts (e.g. Revel Digital `.webapp` zip bundles) DIRECTLY to storage without the\r\nbytes streaming through the API. After uploading, call\r\n`POST /media/uploads/{id}/finalize` to ingest the object into the media library.\r\n            \r\nThe account is always derived from the authenticated key/token — never from the body.\r\nThe presigned URL is scoped to a single object key under the account's namespace, so it\r\ncan never overwrite another account's objects.\r\n            \r\nThree-step flow:\r\n```\r\n# 1) Request a slot\r\ncurl -X POST \"https://api.reveldigital.com/api/media/uploads\" \\\r\n     -H \"X-Reveldigital-Apikey: <API_KEY>\" \\\r\n     -H \"Content-Type: application/json\" \\\r\n     -d '{ \"name\": \"myapp.webapp\", \"group_id\": \"<GROUP_ID>\", \"tags\": [\"env=Production\"], \"content_type\": \"application/zip\" }'\r\n            \r\n# 2) Upload the bytes straight to S3 (Content-Type MUST match the returned header)\r\ncurl -T myapp.webapp -H \"Content-Type: application/zip\" \"<upload_url>\"\r\n            \r\n# 3) Finalize / ingest\r\ncurl -X POST \"https://api.reveldigital.com/api/media/uploads/<id>/finalize\" \\\r\n     -H \"X-Reveldigital-Apikey: <API_KEY>\"\r\n```\r\n            \r\nAll media types supported by the multipart upload work here too (images, audio, video,\r\npresentations, PDF, and `.webapp` bundles): finalize downloads the staged object to\r\nthe server and runs the SAME ingestion pipeline, so video is transcoded just as it is for\r\na multipart upload.",
        "operationId": "PostMediaUploadSlot",
        "requestBody": {
          "description": "Upload slot request",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MediaUploadRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Returns the created upload slot",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MediaUploadResponse"
                }
              }
            }
          },
          "400": {
            "description": "If the request is invalid (bad name, file type, group, or size)"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/media/uploads/{id}": {
      "get": {
        "tags": [
          "Media"
        ],
        "summary": "Get the status of a presigned upload slot.",
        "operationId": "GetMediaUploadStatus",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Upload slot id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns the slot status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MediaUploadStatus"
                }
              }
            }
          },
          "404": {
            "description": "If the slot does not exist, has expired, or belongs to another account"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "head": {
        "tags": [
          "Media"
        ],
        "summary": "Lightweight status check for a presigned upload slot. Returns the SAME state as\r\n`GET /media/uploads/{id}` but with NO body — the status is carried in the\r\n`X-Reveldigital-Upload-Status` header (`pending`, `uploaded`, or\r\n`completed`) and, once finalized, the media id in `X-Reveldigital-Media-Id`. This\r\nlets a client cheaply poll for completion without transferring or parsing a JSON body.",
        "operationId": "HeadMediaUploadStatus",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Upload slot id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The slot exists; the status is in the response headers."
          },
          "404": {
            "description": "If the slot does not exist, has expired, or belongs to another account."
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/media/uploads/{id}/finalize": {
      "post": {
        "tags": [
          "Media"
        ],
        "summary": "Finalize a presigned upload slot, ingesting the uploaded object into the media library.",
        "description": "Verifies the object exists in S3 (HeadObject), validates its size against the configured\r\nmaximum, downloads the staged object to the shared local `Uploads` disk, and runs the\r\nSAME ingestion + media-type detection as the multipart upload (malware scan, dimensions,\r\nhashing, transcoding, replication) — so a `.webapp` is registered as a webapp and a\r\nvideo is transcoded. Returns the created media. This call is idempotent — calling it again\r\nreturns the same media record.",
        "operationId": "PostMediaUploadFinalize",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Upload slot id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Returns the created media",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Media"
                }
              }
            }
          },
          "400": {
            "description": "If the object is missing or exceeds the maximum allowed size"
          },
          "404": {
            "description": "If the slot does not exist, has expired, or belongs to another account"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/media/import": {
      "post": {
        "tags": [
          "Media"
        ],
        "summary": "Import a file from a URL.",
        "operationId": "PostMediaImport",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "description": "URL of the file to import",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group_id",
            "in": "query",
            "description": "Media group Id",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Returns the newly created media",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Media"
                }
              }
            }
          },
          "400": {
            "description": "If the API key is invalid or upload was not supplied"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/playlists": {
      "get": {
        "tags": [
          "Playlists"
        ],
        "summary": "Gets all playlists in an account.",
        "description": "",
        "operationId": "GetPlaylists",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Optional playlist Id to filter by",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "in": "query",
            "description": "Optional number of items to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Optional number of page to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "group_id",
            "in": "query",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "group_name",
            "in": "query",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns an array of playlists",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Playlist"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Playlists"
        ],
        "summary": "Create a new playlist.",
        "operationId": "PostPlaylist",
        "requestBody": {
          "description": "Playlist to create",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Playlist"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Returns the newly-created playlist",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Playlist"
                }
              }
            }
          },
          "400": {
            "description": "If the playlist is null or invalid"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/playlists/{id}": {
      "get": {
        "tags": [
          "Playlists"
        ],
        "summary": "Gets a playlist by ID.",
        "description": "",
        "operationId": "GetPlaylistById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Playlist Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns the playlist matching the ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Playlist"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Playlists"
        ],
        "summary": "Put a playlist. Replaces a playlist with the one provided.",
        "operationId": "PutPlaylist",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Playlist Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Playlist",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Playlist"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Playlists"
        ],
        "summary": "Delete a playlist.",
        "operationId": "DeletePlaylist",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Playlist Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "patch": {
        "tags": [
          "Playlists"
        ],
        "summary": "Patch a playlist. Patch allows partial updates by targeting specific properties of the playlist.\r\nUses the JSON Patch syntax (http://jsonpatch.com)",
        "operationId": "PatchPlaylist",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Playlist Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Patch document",
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/JsonPatchDocument"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/playlists/groups": {
      "get": {
        "tags": [
          "Playlists"
        ],
        "summary": "Gets playlist groups in the account.",
        "description": "",
        "operationId": "GetPlaylistGroups",
        "parameters": [
          {
            "name": "tree",
            "in": "query",
            "description": "Optional hierarchical data format",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "id",
            "in": "query",
            "description": "Optional group id",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "in": "query",
            "description": "Optional number of items to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Optional number of page to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns an array of playlist groups",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Group"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Playlists"
        ],
        "summary": "Create a new playlist group.",
        "operationId": "PostPlaylistGroup",
        "requestBody": {
          "description": "Playlist group",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Returns the newly-created item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Group"
                }
              }
            }
          },
          "400": {
            "description": "If the item is null"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/playlists/groups/{id}": {
      "put": {
        "tags": [
          "Playlists"
        ],
        "summary": "Updates a playlist group.",
        "operationId": "PutPlaylistGroup",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Group id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Device group",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Playlists"
        ],
        "summary": "Delete a playlist group.",
        "description": "Group must be empty.",
        "operationId": "DeletePlaylistGroup",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Playlist group Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/report": {
      "get": {
        "tags": [
          "Report"
        ],
        "summary": "Returns a list of reports available for export.",
        "operationId": "GetReportById",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Optional report id filter",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Report"
                  },
                  "description": "A collection of RevelDigital.Core.PublicApi.Models.Report items for XML serialization."
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/report/export": {
      "post": {
        "tags": [
          "Report"
        ],
        "summary": "Generate and export a report.",
        "parameters": [
          {
            "name": "exclude_body",
            "in": "query",
            "description": "Exclude the generated report body in the response.\r\n            This report is always available at the URL provided in the X-RevelDigital-GeneratedReportUrl response header value.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "description": "Report parameters",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReportExportPostBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/schedules": {
      "get": {
        "tags": [
          "Schedules"
        ],
        "summary": "Gets schedules in an account.",
        "operationId": "GetSchedules",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Optional schedule Id to filter by",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "in": "query",
            "description": "Optional number of items to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Optional number of page to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "group_id",
            "in": "query",
            "description": "Optional schedule group Id",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "group_name",
            "in": "query",
            "description": "Optional group name to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "device_id",
            "in": "query",
            "description": "Optional schedule Id to filter by",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Schedule"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Schedules"
        ],
        "summary": "Creates a new schedule.",
        "operationId": "PostSchedule",
        "requestBody": {
          "description": "",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScheduleRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Schedule"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/schedules/{id}": {
      "get": {
        "tags": [
          "Schedules"
        ],
        "summary": "Gets a schedule by ID.",
        "operationId": "GetScheduleById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Schedule Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Schedule"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Schedules"
        ],
        "summary": "Update schedule.",
        "operationId": "PutSchedule",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Schedule Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScheduleRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "patch": {
        "tags": [
          "Schedules"
        ],
        "summary": "Patch a schedule. Patch allows partial updates by targeting specific properties of the schedule.\r\nUses the JSON Patch syntax (http://jsonpatch.com)",
        "operationId": "PatchSchedule",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Schedule Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Patch update",
          "content": {
            "application/json-patch+json": {
              "schema": {
                "$ref": "#/components/schemas/JsonPatchDocument"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Schedules"
        ],
        "summary": "Delete a schedule.",
        "operationId": "DeleteSchedule",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Schedule Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/schedules/groups": {
      "get": {
        "tags": [
          "Schedules"
        ],
        "summary": "Gets schedule groups in the account.",
        "operationId": "GetScheduleGroups",
        "parameters": [
          {
            "name": "tree",
            "in": "query",
            "description": "Optional hierarchical data format",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "id",
            "in": "query",
            "description": "Optional group id",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "in": "query",
            "description": "Optional number of items to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Optional number of page to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Group"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Schedules"
        ],
        "summary": "Create a new schedule group.",
        "operationId": "PostScheduleGroup",
        "requestBody": {
          "description": "Schedule group",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Group"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/schedules/groups/{id}": {
      "put": {
        "tags": [
          "Schedules"
        ],
        "summary": "Updates a schedule group.",
        "operationId": "PutScheduleGroup",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Schedule group Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Schedule group",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Schedules"
        ],
        "summary": "Delete a schedule group.",
        "description": "Group must be empty.",
        "operationId": "DeleteScheduleGroup",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Schedule group Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/templates": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "Gets all templates in an account.",
        "description": "",
        "operationId": "GetTemplates",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Optional template id to filter by",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "in": "query",
            "description": "Optional number of items to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Optional number of page to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "group_id",
            "in": "query",
            "description": "Optional template group Id",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "group_name",
            "in": "query",
            "description": "Optional group name to filter by",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns an array of templates",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Template"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/templates/{id}": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "Gets a template by ID.",
        "description": "",
        "operationId": "GetTemplateById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns the template matching the ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Template"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Templates"
        ],
        "summary": "Update a template using PUT. Full resource update.",
        "operationId": "PutTemplate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Template update data",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TemplateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Template"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "patch": {
        "tags": [
          "Templates"
        ],
        "summary": "Patch a template. Patch allows partial updates by targeting specific properties of the template.\r\nUses the JSON Patch syntax (http://jsonpatch.com)",
        "operationId": "PatchTemplate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Patch document",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TemplateRequestJsonPatchDocument"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Template"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Templates"
        ],
        "summary": "Delete a template.",
        "operationId": "DeleteTemplate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/templates/groups": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "Gets template groups in the account.",
        "description": "",
        "operationId": "GetTemplateGroups",
        "parameters": [
          {
            "name": "tree",
            "in": "query",
            "description": "Optional hierarchical data format",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "id",
            "in": "query",
            "description": "Optional template id to filter by",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "in": "query",
            "description": "Optional number of items to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Optional number of page to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns an array of playlist groups",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Group"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Templates"
        ],
        "summary": "Create a new template group.",
        "operationId": "PostTemplateGroup",
        "requestBody": {
          "description": "Template group",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Returns the newly-created item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Group"
                }
              }
            }
          },
          "400": {
            "description": "If the item is null"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/templates/groups/{id}": {
      "put": {
        "tags": [
          "Templates"
        ],
        "summary": "Updates a template group.",
        "operationId": "PutTemplateGroup",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Group id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Template group",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GroupRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Templates"
        ],
        "summary": "Delete a template group.",
        "description": "Group must be empty.",
        "operationId": "DeleteTemplateGroup",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Template group Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/templates/{templateId}/modules/{moduleId}": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "Gets a specific module/zone within a template.\r\nModules (also called zones) define rectangular content areas on the screen.",
        "operationId": "GetTemplateModule",
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "moduleId",
            "in": "path",
            "description": "Module/zone Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns the module/zone"
          },
          "404": {
            "description": "Template or module/zone not found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Templates"
        ],
        "summary": "Update a module/zone within a template using PUT. Full resource update.\r\nModules/zones define rectangular content areas on the screen.",
        "operationId": "PutTemplateModule",
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "moduleId",
            "in": "path",
            "description": "Module/zone Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Module/zone update data",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ModuleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Module"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "patch": {
        "tags": [
          "Templates"
        ],
        "summary": "Patch a module/zone within a template. Patch allows partial updates by targeting specific properties.\r\nUses the JSON Patch syntax (http://jsonpatch.com). Modules/zones define content areas on screen.",
        "operationId": "PatchTemplateModule",
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "moduleId",
            "in": "path",
            "description": "Module/zone Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "JSON Patch document",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ModuleRequestJsonPatchDocument"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Module"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Templates"
        ],
        "summary": "Delete a module/zone from a template.\r\nRemoves a content area from the template layout.",
        "operationId": "DeleteTemplateModule",
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "moduleId",
            "in": "path",
            "description": "Module/zone Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/templates/{templateId}/modules": {
      "post": {
        "tags": [
          "Templates"
        ],
        "summary": "Create a new module/zone within a template.\r\nModules/zones define rectangular content areas where playlist content is displayed.",
        "operationId": "PostTemplateModule",
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Module/zone configuration data",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ModuleRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Returns the newly-created module/zone",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Module"
                }
              }
            }
          },
          "400": {
            "description": "If the request is invalid"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/templates/{templateId}/modules/{moduleId}/options": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "Gets all configuration options for a specific module/zone.\r\nOptions store settings like timezone for Clock zones, location for Weather zones, etc.",
        "operationId": "GetModuleOptions",
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "moduleId",
            "in": "path",
            "description": "Module/zone Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Templates"
        ],
        "summary": "Create a new configuration option for a module/zone.\r\nOptions customize module/zone behavior (e.g., 'timezone', 'location', 'url').",
        "operationId": "PostModuleOption",
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "moduleId",
            "in": "path",
            "description": "Module/zone Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Option configuration data",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ModuleOptionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModuleOption"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Templates"
        ],
        "summary": "Replace all configuration options for a module/zone (bulk set).\r\nThis removes all existing options and creates new ones from the provided array.\r\nUseful for resetting module/zone configuration or applying presets.",
        "operationId": "SetModuleOptions",
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "moduleId",
            "in": "path",
            "description": "Module/zone Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Array of options to set",
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ModuleOptionRequest"
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/templates/{templateId}/modules/{moduleId}/options/{optionId}": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "Gets a specific configuration option from a module/zone.",
        "operationId": "GetModuleOption",
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "moduleId",
            "in": "path",
            "description": "Module/zone Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "optionId",
            "in": "path",
            "description": "Option Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Templates"
        ],
        "summary": "Update a module/zone configuration option using PUT.",
        "operationId": "PutModuleOption",
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "moduleId",
            "in": "path",
            "description": "Module/zone Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "optionId",
            "in": "path",
            "description": "Option Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Option update data",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ModuleOptionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModuleOption"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "patch": {
        "tags": [
          "Templates"
        ],
        "summary": "Patch a module/zone configuration option. Allows partial updates.\r\nUses the JSON Patch syntax (http://jsonpatch.com)",
        "operationId": "PatchModuleOption",
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "moduleId",
            "in": "path",
            "description": "Module/zone Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "optionId",
            "in": "path",
            "description": "Option Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "JSON Patch document",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ModuleOptionRequestJsonPatchDocument"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModuleOption"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Templates"
        ],
        "summary": "Delete a module/zone configuration option.",
        "operationId": "DeleteModuleOption",
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "description": "Template Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "moduleId",
            "in": "path",
            "description": "Module/zone Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "optionId",
            "in": "path",
            "description": "Option Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/users": {
      "get": {
        "tags": [
          "Users"
        ],
        "summary": "Gets all users in an account.",
        "description": "",
        "operationId": "GetUsers",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "description": "Optional User Id to filter by",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "in": "query",
            "description": "Optional number of items to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Optional number of page to return",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns an array of users",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/User"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    },
    "/users/{id}": {
      "get": {
        "tags": [
          "Users"
        ],
        "summary": "Gets a user by ID.",
        "description": "",
        "operationId": "GetUserById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "User Id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Returns the user matching the ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [
              "webapi"
            ]
          },
          {
            "ApiKeyInHeader": [ ]
          },
          {
            "ApiKeyInQuery": [ ]
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "Account": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The account id",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The account name",
            "nullable": true
          },
          "tags": {
            "type": "string",
            "description": "Tags associated with this account",
            "nullable": true
          },
          "business_name": {
            "type": "string",
            "description": "The business name",
            "nullable": true
          },
          "address_1": {
            "type": "string",
            "description": "The address line 1",
            "nullable": true
          },
          "address_2": {
            "type": "string",
            "description": "The address line 2",
            "nullable": true
          },
          "city": {
            "type": "string",
            "description": "The city",
            "nullable": true
          },
          "state": {
            "type": "string",
            "description": "The state",
            "nullable": true
          },
          "postal_code": {
            "type": "string",
            "description": "The postal code",
            "nullable": true
          },
          "country": {
            "type": "string",
            "description": "The country",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "The phone number",
            "nullable": true
          },
          "fax": {
            "type": "string",
            "description": "The fax number",
            "nullable": true
          },
          "primary_contact_id": {
            "type": "string",
            "description": "The primary contact user id",
            "nullable": true
          },
          "secondary_contact_id": {
            "type": "string",
            "description": "The secondary contact user id",
            "nullable": true
          },
          "created_on": {
            "type": "string",
            "description": "The created on date",
            "format": "date-time",
            "nullable": true
          },
          "timeZone": {
            "type": "string",
            "description": "The time zone",
            "nullable": true
          },
          "logo_url": {
            "type": "string",
            "description": "The logo url",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a customer account in the RevelDigital platform.\r\nAn account is the top-level entity that owns devices, media, playlists, templates, and schedules."
      },
      "AdHawkAgeRange": {
        "enum": [
          "Unknown",
          "Under18",
          "Age18To24",
          "Age25To34",
          "Age35To44",
          "Age45To54",
          "Age55To64",
          "Age65To74",
          "Over74"
        ],
        "type": "string",
        "description": "Age range classification for audience analytics"
      },
      "AdHawkAudienceMetrics": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "string",
            "description": "The device ID",
            "nullable": true
          },
          "device_name": {
            "type": "string",
            "description": "The device name",
            "nullable": true
          },
          "period_start": {
            "type": "string",
            "description": "Start of the time period for these metrics",
            "format": "date-time"
          },
          "period_end": {
            "type": "string",
            "description": "End of the time period for these metrics",
            "format": "date-time"
          },
          "total_impressions": {
            "type": "integer",
            "description": "Total number of impressions detected",
            "format": "int64"
          },
          "unique_visitors": {
            "type": "integer",
            "description": "Number of unique visitors (based on anonymous user IDs)",
            "format": "int64"
          },
          "avg_dwell_time": {
            "type": "number",
            "description": "Average dwell time in seconds",
            "format": "double",
            "nullable": true
          },
          "male_count": {
            "type": "integer",
            "description": "Number of male visitors detected",
            "format": "int64"
          },
          "female_count": {
            "type": "integer",
            "description": "Number of female visitors detected",
            "format": "int64"
          },
          "unknown_gender_count": {
            "type": "integer",
            "description": "Number of visitors with unknown gender",
            "format": "int64"
          },
          "age_under_18": {
            "type": "integer",
            "description": "Number of visitors under 18 years old",
            "format": "int64"
          },
          "age_18_to_24": {
            "type": "integer",
            "description": "Number of visitors 18-24 years old",
            "format": "int64"
          },
          "age_25_to_34": {
            "type": "integer",
            "description": "Number of visitors 25-34 years old",
            "format": "int64"
          },
          "age_35_to_44": {
            "type": "integer",
            "description": "Number of visitors 35-44 years old",
            "format": "int64"
          },
          "age_45_to_54": {
            "type": "integer",
            "description": "Number of visitors 45-54 years old",
            "format": "int64"
          },
          "age_55_to_64": {
            "type": "integer",
            "description": "Number of visitors 55-64 years old",
            "format": "int64"
          },
          "age_65_to_74": {
            "type": "integer",
            "description": "Number of visitors 65-74 years old",
            "format": "int64"
          },
          "age_over_74": {
            "type": "integer",
            "description": "Number of visitors over 74 years old",
            "format": "int64"
          },
          "motion_count": {
            "type": "integer",
            "description": "Number of motion sensor detections",
            "format": "int64"
          },
          "audience_count": {
            "type": "integer",
            "description": "Number of audience/face detections",
            "format": "int64"
          },
          "ble_count": {
            "type": "integer",
            "description": "Number of BLE beacon detections",
            "format": "int64"
          },
          "wifi_count": {
            "type": "integer",
            "description": "Number of WiFi proximity detections",
            "format": "int64"
          }
        },
        "additionalProperties": false,
        "description": "Aggregated audience metrics for a device over a time period"
      },
      "AdHawkDatasetPostBody": {
        "required": [
          "dataset_type"
        ],
        "type": "object",
        "properties": {
          "dataset_type": {
            "$ref": "#/components/schemas/AdHawkDatasetType"
          },
          "interval_type": {
            "$ref": "#/components/schemas/AdHawkIntervalType"
          },
          "device_id": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Array of devices by Id. REQUIRED",
            "nullable": true
          },
          "start_date": {
            "type": "string",
            "description": "Report start date. REQUIRED\r\n\r\nProvide in ISO 8601 format: YYYY-MM-DDThh:mm:ssZ",
            "format": "date-time",
            "nullable": true
          },
          "end_date": {
            "type": "string",
            "description": "Report end date. REQUIRED\r\n\r\nProvide in ISO 8601 format: YYYY-MM-DDThh:mm:ssZ",
            "format": "date-time",
            "nullable": true
          },
          "compare_start_time": {
            "type": "string",
            "description": "Report start time.\r\n\r\nProvide in ISO 8601 format: YYYY-MM-DDThh:mm:ssZ",
            "format": "date-time",
            "nullable": true
          },
          "compare_end_time": {
            "type": "string",
            "description": "Report end time.\r\n\r\nProvide in ISO 8601 format: YYYY-MM-DDThh:mm:ssZ",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents the body of a request for an AdHawk dataset."
      },
      "AdHawkDatasetType": {
        "enum": [
          "ImpressionTotals",
          "GenderTotals",
          "DailyImpressions",
          "DwellRange",
          "AgeRange",
          "DayOfWeekByHourHeatmap",
          "ImpressionsByGenderByDay",
          "ImpressionsByAgeGroupByDay",
          "GenderAgeHeatmap",
          "DailyAverageDwell",
          "ImpressionsByDeviceAndPingType",
          "ImpressionsByMedia",
          "EventsTotals",
          "DailyEvents",
          "EventsByEventName",
          "EventsByDeviceName",
          "EventsByDeviceCountry",
          "AverageDwellByEventName",
          "EventsBySession",
          "AverageDwellBySession",
          "AverageEventsByNameAndSession",
          "NetworkPingTotals",
          "NetworkAlertTotals",
          "NetworkAlertsByLocation"
        ],
        "type": "string",
        "description": "This enumeration defines the different categories of datasets that can be used for analytics\r\nand reporting within the AdHawk platform. Each value corresponds to a specific type of data aggregation or\r\nanalysis, such as impressions, demographics, dwell times, events, or network-related metrics.\r\n\r\nThe following AdHawk dataset types are available:\r\n\r\nImpressionTotals: Total audience impressions for the given time period\r\nGenderTotals: Audience impression totals grouped by gender\r\nDailyImpressions: Total impressions grouped by interval (day, week, month, hour, minute)\r\nDwellRange: Impressions grouped by the following dwell ranges in seconds: 0-5, 5-10, 10-15, 15-30, 30-45, 45-60, 60-120, 120+\r\nAgeRange: Impressions grouped by the following age ranges: 0-17, 18-24, 25-34, 35-44, 45-54, 55-64, 65-74, 75+\r\nDayOfWeekByHourHeatmap: Impressions grouped by day of week and hour of day\r\nImpressionsByGenderByDay: Impressions grouped by gender and day\r\nImpressionsByAgeGroupByDay: Impressions grouped by age group and day\r\nGenderAgeHeatmap: Impressions grouped by gender and age\r\nDailyAverageDwell: Average dwell time by day\r\nImpressionsByDeviceAndPingType: Impressions grouped by device and ping type\r\nImpressionsByMedia: Impressions grouped by media\r\n\r\nEventsTotals: Total events and sessions for the given time period\r\nDailyEvents: Total events grouped by interval (day, week, month, hour, minute)\r\nEventsByEventName: Total events grouped by event name\r\nEventsByDeviceName: Total events grouped by device name\r\nEventsByDeviceCountry: Total events grouped by device country\r\nAverageDwellByEventName: Average dwell time grouped by event name\r\nEventsBySession: Total events grouped by session\r\nAverageDwellBySession: Average dwell time grouped by session\r\nAverageEventsByNameAndSession: Average events grouped by event name and session\r\n\r\nNetworkPingTotals: Total device pings including percetage of time active, downloading, and playing. Grouped by interval (day, week, month, hour, minute)\r\nNetworkAlertTotals: Totals alerts grouped by alert type and interval (day, week, month, hour, minute)\r\nNetworkAlertsByLocation: Alerts grouped by location"
      },
      "AdHawkDeviceMediaImpressions": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "string",
            "description": "The device ID",
            "nullable": true
          },
          "device_name": {
            "type": "string",
            "description": "The device name",
            "nullable": true
          },
          "total_impressions": {
            "type": "integer",
            "description": "Total number of impressions that occurred during media playback",
            "format": "int64"
          },
          "unique_media_count": {
            "type": "integer",
            "description": "Number of unique media files played with audience present",
            "format": "int64"
          },
          "net_reach": {
            "type": "integer",
            "description": "Net reach - count of impressions with dwell time > 100ms (actually viewed)",
            "format": "int64"
          },
          "ots_percentage": {
            "type": "number",
            "description": "OTS (Opportunity To See) percentage - ratio of net reach to total impressions",
            "format": "double",
            "nullable": true
          },
          "avg_dwell_time": {
            "type": "number",
            "description": "Average dwell time in seconds for impressions with dwell > 100ms",
            "format": "double",
            "nullable": true
          },
          "male_count": {
            "type": "integer",
            "description": "Count of male impressions",
            "format": "int64"
          },
          "female_count": {
            "type": "integer",
            "description": "Count of female impressions",
            "format": "int64"
          },
          "unknown_gender_count": {
            "type": "integer",
            "description": "Count of impressions with unknown gender",
            "format": "int64"
          },
          "avg_age": {
            "type": "number",
            "description": "Average age of audience members (if available)",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Device-level media impression statistics showing OTS metrics per device."
      },
      "AdHawkDeviceMetrics": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "string",
            "description": "The device ID",
            "nullable": true
          },
          "device_name": {
            "type": "string",
            "description": "The device name",
            "nullable": true
          },
          "period_start": {
            "type": "string",
            "description": "Start of the time period for these metrics",
            "format": "date-time"
          },
          "period_end": {
            "type": "string",
            "description": "End of the time period for these metrics",
            "format": "date-time"
          },
          "avg_cpu_usage": {
            "type": "number",
            "description": "Average CPU usage percentage during the period",
            "format": "double",
            "nullable": true
          },
          "max_cpu_usage": {
            "type": "number",
            "description": "Maximum CPU usage percentage during the period",
            "format": "double",
            "nullable": true
          },
          "avg_memory_usage": {
            "type": "number",
            "description": "Average memory usage percentage during the period",
            "format": "double",
            "nullable": true
          },
          "max_memory_usage": {
            "type": "number",
            "description": "Maximum memory usage percentage during the period",
            "format": "double",
            "nullable": true
          },
          "avg_disk_usage": {
            "type": "number",
            "description": "Average disk usage percentage during the period",
            "format": "double",
            "nullable": true
          },
          "total_tx_bytes": {
            "type": "integer",
            "description": "Total bytes transmitted during the period",
            "format": "int64",
            "nullable": true
          },
          "total_rx_bytes": {
            "type": "integer",
            "description": "Total bytes received during the period",
            "format": "int64",
            "nullable": true
          },
          "uptime_percentage": {
            "type": "number",
            "description": "Percentage of time the device was online (0-100)",
            "format": "float",
            "nullable": true
          },
          "ping_count": {
            "type": "integer",
            "description": "Number of pings received during the period",
            "format": "int64"
          },
          "alert_count": {
            "type": "integer",
            "description": "Number of alerts generated during the period",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Aggregated device health metrics over a time period"
      },
      "AdHawkDevicePlayStats": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "string",
            "description": "The device ID",
            "nullable": true
          },
          "device_name": {
            "type": "string",
            "description": "The device name",
            "nullable": true
          },
          "total_plays": {
            "type": "integer",
            "description": "Total number of media files played on this device",
            "format": "int64"
          },
          "total_duration": {
            "type": "integer",
            "description": "Total duration of all plays in seconds",
            "format": "int64"
          },
          "avg_duration": {
            "type": "number",
            "description": "Average play duration in seconds",
            "format": "double",
            "nullable": true
          },
          "file_count": {
            "type": "integer",
            "description": "Number of unique media files played on this device",
            "format": "int64"
          },
          "first_play": {
            "type": "string",
            "description": "First play timestamp for the period",
            "format": "date-time",
            "nullable": true
          },
          "last_play": {
            "type": "string",
            "description": "Last play timestamp for the period",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Device play statistics - aggregated play counts and duration for a device\r\nUseful for DooH reporting to determine content playback by device"
      },
      "AdHawkEventFlow": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "description": "Source event name with index suffix (e.g., \"Button Click1\")",
            "nullable": true
          },
          "target": {
            "type": "string",
            "description": "Target event name with index suffix (e.g., \"Page View2\")",
            "nullable": true
          },
          "value": {
            "type": "integer",
            "description": "Count of transitions from source to target",
            "format": "int64"
          },
          "event_index": {
            "type": "integer",
            "description": "Position in the event sequence (1 = first transition, 2 = second, etc.)",
            "format": "int32"
          },
          "avg_dwell": {
            "type": "number",
            "description": "Average dwell time in seconds between source and target events",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Event flow edge representing a transition between events in a user session.\r\nUseful for building Sankey diagrams and analyzing user navigation paths."
      },
      "AdHawkEventLog": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for this event log entry",
            "nullable": true
          },
          "timestamp": {
            "type": "string",
            "description": "Timestamp when the event occurred",
            "format": "date-time"
          },
          "device_id": {
            "type": "string",
            "description": "The device ID where the event occurred",
            "nullable": true
          },
          "session_id": {
            "type": "string",
            "description": "Session identifier for grouping related events",
            "nullable": true
          },
          "event_name": {
            "type": "string",
            "description": "Name of the event (e.g., \"button_click\", \"page_view\")",
            "nullable": true
          },
          "properties": {
            "type": "object",
            "additionalProperties": {
              "nullable": true
            },
            "description": "Additional properties associated with the event as key-value pairs",
            "nullable": true
          },
          "utc_offset": {
            "type": "integer",
            "description": "UTC offset of the device at the time of the event",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a custom event log entry from a device"
      },
      "AdHawkEventMetrics": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "string",
            "description": "The device ID",
            "nullable": true
          },
          "device_name": {
            "type": "string",
            "description": "The device name",
            "nullable": true
          },
          "event_name": {
            "type": "string",
            "description": "The event name (when grouping by event)",
            "nullable": true
          },
          "period_start": {
            "type": "string",
            "description": "Start of the time period for these metrics",
            "format": "date-time"
          },
          "period_end": {
            "type": "string",
            "description": "End of the time period for these metrics",
            "format": "date-time"
          },
          "total_events": {
            "type": "integer",
            "description": "Total number of events",
            "format": "int64"
          },
          "unique_sessions": {
            "type": "integer",
            "description": "Number of unique sessions",
            "format": "int64"
          },
          "unique_event_names": {
            "type": "integer",
            "description": "Number of unique event names (when not grouping by event)",
            "format": "int64",
            "nullable": true
          },
          "unique_devices": {
            "type": "integer",
            "description": "Number of unique devices (when not grouping by device)",
            "format": "int64",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Aggregated event metrics for a device over a time period"
      },
      "AdHawkGender": {
        "enum": [
          "Unknown",
          "Female",
          "Male"
        ],
        "type": "string",
        "description": "Gender classification for audience analytics"
      },
      "AdHawkHeatMapData": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "string",
            "description": "The device ID",
            "nullable": true
          },
          "latitude": {
            "type": "number",
            "description": "Latitude coordinate for the location",
            "format": "double",
            "nullable": true
          },
          "longitude": {
            "type": "number",
            "description": "Longitude coordinate for the location",
            "format": "double",
            "nullable": true
          },
          "day": {
            "type": "string",
            "description": "Day or period for the aggregated data",
            "format": "date-time"
          },
          "count": {
            "type": "integer",
            "description": "Total impression count for this location and period",
            "format": "int64"
          },
          "ble_count": {
            "type": "integer",
            "description": "Count of BLE beacon impressions",
            "format": "int64"
          },
          "wifi_count": {
            "type": "integer",
            "description": "Count of WiFi impressions",
            "format": "int64"
          },
          "motion_count": {
            "type": "integer",
            "description": "Count of motion sensor impressions",
            "format": "int64"
          },
          "audience_count": {
            "type": "integer",
            "description": "Count of audience/face detection impressions",
            "format": "int64"
          }
        },
        "additionalProperties": false,
        "description": "Geographic heatmap data point aggregated by location and time period.\r\nUseful for geographic visualizations and location-based analytics."
      },
      "AdHawkImpression": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for this impression entry",
            "nullable": true
          },
          "timestamp": {
            "type": "string",
            "description": "Timestamp when the impression was recorded",
            "format": "date-time"
          },
          "device_id": {
            "type": "string",
            "description": "The device ID where the impression was detected",
            "nullable": true
          },
          "type": {
            "type": "integer",
            "description": "Type of impression detection.\r\nTypes are bitfield values:\r\n<list type=\"bullet\"><item><description>8 = motion</description></item><item><description>64 = audience</description></item><item><description>128 = ble</description></item><item><description>256 = wifi</description></item></list>",
            "format": "int32"
          },
          "dwell_time": {
            "type": "integer",
            "description": "Dwell time in milliseconds - how long the visitor was detected",
            "format": "int64",
            "nullable": true
          },
          "user_id": {
            "type": "string",
            "description": "Anonymous user identifier for tracking unique visitors",
            "nullable": true
          },
          "gender": {
            "$ref": "#/components/schemas/AdHawkGender"
          },
          "age": {
            "type": "integer",
            "description": "Estimated age of the visitor",
            "format": "int32",
            "nullable": true
          },
          "age_range": {
            "$ref": "#/components/schemas/AdHawkAgeRange"
          },
          "rssi": {
            "type": "integer",
            "description": "Received Signal Strength Indicator for BLE/WiFi detections",
            "format": "int32",
            "nullable": true
          },
          "utc_offset": {
            "type": "integer",
            "description": "UTC offset of the device at the time of detection",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents an audience impression/detection entry"
      },
      "AdHawkIntervalType": {
        "enum": [
          "Minute",
          "Hour",
          "Day",
          "Week",
          "Month"
        ],
        "type": "string"
      },
      "AdHawkMediaImpressions": {
        "type": "object",
        "properties": {
          "file_id": {
            "type": "string",
            "description": "The file/media ID",
            "nullable": true
          },
          "file_name": {
            "type": "string",
            "description": "The file/media name",
            "nullable": true
          },
          "total_impressions": {
            "type": "integer",
            "description": "Total number of impressions that occurred during media playback",
            "format": "int64"
          },
          "unique_device_count": {
            "type": "integer",
            "description": "Number of unique devices that played the media with audience present",
            "format": "int64"
          },
          "net_reach": {
            "type": "integer",
            "description": "Net reach - count of impressions with dwell time > 100ms (actually viewed)",
            "format": "int64"
          },
          "ots_percentage": {
            "type": "number",
            "description": "OTS (Opportunity To See) percentage - ratio of net reach to total impressions",
            "format": "double",
            "nullable": true
          },
          "ots_per_device": {
            "type": "number",
            "description": "OTS count per unique device",
            "format": "double",
            "nullable": true
          },
          "avg_dwell_time": {
            "type": "number",
            "description": "Average dwell time in seconds for impressions with dwell > 100ms",
            "format": "double",
            "nullable": true
          },
          "male_count": {
            "type": "integer",
            "description": "Count of male impressions",
            "format": "int64"
          },
          "female_count": {
            "type": "integer",
            "description": "Count of female impressions",
            "format": "int64"
          },
          "unknown_gender_count": {
            "type": "integer",
            "description": "Count of impressions with unknown gender",
            "format": "int64"
          },
          "avg_age": {
            "type": "number",
            "description": "Average age of audience members (if available)",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Media impression statistics showing OTS (Opportunity To See) metrics.\r\nJoins audience/impression data with media play logs to determine which audience\r\nmembers had an opportunity to see specific media content."
      },
      "AdHawkMediaPlayStats": {
        "type": "object",
        "properties": {
          "file_id": {
            "type": "string",
            "description": "The media file ID",
            "nullable": true
          },
          "file_name": {
            "type": "string",
            "description": "The media file name",
            "nullable": true
          },
          "total_plays": {
            "type": "integer",
            "description": "Total number of times this media was played",
            "format": "int64"
          },
          "total_duration": {
            "type": "integer",
            "description": "Total duration of all plays in seconds",
            "format": "int64"
          },
          "avg_duration": {
            "type": "number",
            "description": "Average play duration in seconds",
            "format": "double",
            "nullable": true
          },
          "device_count": {
            "type": "integer",
            "description": "Number of unique devices that played this media",
            "format": "int64"
          }
        },
        "additionalProperties": false,
        "description": "Media play statistics - aggregated play counts for a media file"
      },
      "AdHawkPingLog": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for this ping log entry",
            "nullable": true
          },
          "timestamp": {
            "type": "string",
            "description": "Timestamp of the ping",
            "format": "date-time"
          },
          "device_id": {
            "type": "string",
            "description": "The device ID that sent the ping",
            "nullable": true
          },
          "type": {
            "type": "integer",
            "description": "Type of ping (alive, downloading, playing, motion)",
            "format": "int32"
          },
          "sub_type": {
            "type": "integer",
            "description": "Subtype of the ping for more granular classification",
            "format": "int32",
            "nullable": true
          },
          "cpu_usage": {
            "type": "number",
            "description": "CPU usage percentage (0-100)",
            "format": "double",
            "nullable": true
          },
          "memory_usage": {
            "type": "number",
            "description": "Memory usage percentage (0-100)",
            "format": "double",
            "nullable": true
          },
          "disk_usage": {
            "type": "number",
            "description": "Disk usage percentage (0-100)",
            "format": "double",
            "nullable": true
          },
          "tx_bytes": {
            "type": "integer",
            "description": "Total bytes transmitted since last ping",
            "format": "int64",
            "nullable": true
          },
          "rx_bytes": {
            "type": "integer",
            "description": "Total bytes received since last ping",
            "format": "int64",
            "nullable": true
          },
          "external_ip_address": {
            "type": "string",
            "description": "External IP address of the device",
            "nullable": true
          },
          "latitude": {
            "type": "number",
            "description": "Latitude coordinate if GPS is available",
            "format": "double",
            "nullable": true
          },
          "longitude": {
            "type": "number",
            "description": "Longitude coordinate if GPS is available",
            "format": "double",
            "nullable": true
          },
          "utc_offset": {
            "type": "integer",
            "description": "UTC offset of the device",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a device ping/heartbeat log entry - records device health and status"
      },
      "AdHawkPlayLog": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for this play log entry",
            "nullable": true
          },
          "timestamp": {
            "type": "string",
            "description": "Timestamp when the content was played",
            "format": "date-time"
          },
          "device_id": {
            "type": "string",
            "description": "The device ID where the content was played",
            "nullable": true
          },
          "file_id": {
            "type": "string",
            "description": "The media file ID that was played",
            "nullable": true
          },
          "file_name": {
            "type": "string",
            "description": "The name of the media file",
            "nullable": true
          },
          "duration": {
            "type": "integer",
            "description": "Duration of the play in seconds",
            "format": "int32",
            "nullable": true
          },
          "type": {
            "type": "integer",
            "description": "Type of play (internal use)",
            "format": "int32",
            "nullable": true
          },
          "utc_offset": {
            "type": "integer",
            "description": "UTC offset of the device at the time of play",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a media play log entry - records when content was played on a device"
      },
      "AdHawkPlayStatsByTime": {
        "type": "object",
        "properties": {
          "device_id": {
            "type": "string",
            "description": "Optional device ID (null if aggregated across all devices)",
            "nullable": true
          },
          "device_name": {
            "type": "string",
            "description": "Optional device name",
            "nullable": true
          },
          "file_id": {
            "type": "string",
            "description": "Optional file ID (null if aggregated across all files)",
            "nullable": true
          },
          "file_name": {
            "type": "string",
            "description": "Optional file name",
            "nullable": true
          },
          "period_start": {
            "type": "string",
            "description": "Start of the time period for these stats",
            "format": "date-time"
          },
          "period_end": {
            "type": "string",
            "description": "End of the time period for these stats",
            "format": "date-time"
          },
          "total_plays": {
            "type": "integer",
            "description": "Total number of plays during this period",
            "format": "int64"
          },
          "total_duration": {
            "type": "integer",
            "description": "Total duration of all plays in seconds",
            "format": "int64"
          },
          "avg_duration": {
            "type": "number",
            "description": "Average play duration in seconds",
            "format": "double",
            "nullable": true
          },
          "device_count": {
            "type": "integer",
            "description": "Number of unique devices (if aggregated by file)",
            "format": "int64",
            "nullable": true
          },
          "file_count": {
            "type": "integer",
            "description": "Number of unique files (if aggregated by device)",
            "format": "int64",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Time-series play statistics aggregated by interval (hour, day, week, etc.)\r\nUseful for DooH reporting to analyze playback trends over time"
      },
      "Alert": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The alert id (encrypted)",
            "nullable": true
          },
          "created_on": {
            "type": "string",
            "description": "The date and time the alert was created",
            "format": "date-time"
          },
          "updated_on": {
            "type": "string",
            "description": "The date and time the alert was last updated",
            "format": "date-time",
            "nullable": true
          },
          "snoozed_until": {
            "type": "string",
            "description": "The date and time until which the alert is snoozed",
            "format": "date-time",
            "nullable": true
          },
          "resolved_on": {
            "type": "string",
            "description": "The date and time the alert was resolved",
            "format": "date-time",
            "nullable": true
          },
          "alert_rule": {
            "$ref": "#/components/schemas/AlertRuleSummary"
          },
          "devices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AlertDevice"
            },
            "description": "The devices affected by this alert",
            "nullable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Indicates if the alert is currently active (not resolved and not snoozed)"
          }
        },
        "additionalProperties": false,
        "description": "Alert model"
      },
      "AlertDevice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The device id (encrypted)",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The device name",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Device associated with an alert"
      },
      "AlertRequest": {
        "type": "object",
        "properties": {
          "snoozed_until": {
            "type": "string",
            "description": "Set to snooze the alert until a specific date/time",
            "format": "date-time",
            "nullable": true
          },
          "resolved_on": {
            "type": "string",
            "description": "Set to resolve the alert",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Alert model used for updating alerts"
      },
      "AlertRequestJsonPatchDocument": {
        "type": "object",
        "properties": {
          "operations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AlertRequestOperation"
            },
            "nullable": true,
            "readOnly": true
          },
          "contractResolver": {
            "$ref": "#/components/schemas/IContractResolver"
          }
        },
        "additionalProperties": false
      },
      "AlertRequestOperation": {
        "type": "object",
        "properties": {
          "operationType": {
            "$ref": "#/components/schemas/OperationType"
          },
          "path": {
            "type": "string",
            "nullable": true
          },
          "op": {
            "type": "string",
            "nullable": true
          },
          "from": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AlertRule": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The alert rule id (encrypted)",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The name of the alert rule",
            "nullable": true
          },
          "rule_set": {
            "type": "string",
            "description": "The rule set configuration as a JSON string. See AlertRuleInput.ruleSet for the full\r\nschema, supported condition types, operators, and value semantics.",
            "nullable": true
          },
          "is_enabled": {
            "type": "boolean",
            "description": "Indicates whether the alert rule is currently enabled and will be evaluated.\r\nWhen false, the rule is stored but never triggers alerts.",
            "nullable": true
          },
          "period": {
            "type": "integer",
            "description": "The look-back / evaluation period, in minutes, used by time-window based conditions.",
            "format": "int32",
            "nullable": true
          },
          "threshold": {
            "type": "integer",
            "description": "A legacy scalar threshold value retained for backward compatibility. Thresholds for new\r\nrules are expressed inside the rule set (AlertRuleInput.ruleSet) via each item's \"value\" instead.",
            "format": "int32",
            "nullable": true
          },
          "webhook_url": {
            "type": "string",
            "description": "Optional HTTPS webhook URL that is invoked (HTTP POST) when the rule triggers.",
            "nullable": true
          },
          "all_devices": {
            "type": "boolean",
            "description": "When true, the rule is evaluated against every device in the account and\r\nRevelDigital.Core.PublicApi.Models.AlertRule.DeviceIds is empty. When false, only RevelDigital.Core.PublicApi.Models.AlertRule.DeviceIds are evaluated.",
            "nullable": true
          },
          "all_users": {
            "type": "boolean",
            "description": "When true, all users in the account are notified and RevelDigital.Core.PublicApi.Models.AlertRule.UserIds is empty.\r\nWhen false, only the users in RevelDigital.Core.PublicApi.Models.AlertRule.UserIds are notified.",
            "nullable": true
          },
          "created_on": {
            "type": "string",
            "description": "The date and time the alert rule was created",
            "format": "date-time",
            "nullable": true
          },
          "updated_on": {
            "type": "string",
            "description": "The date and time the alert rule was last updated",
            "format": "date-time",
            "nullable": true
          },
          "device_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The devices explicitly associated with the rule (encrypted ids).\r\nEmpty when RevelDigital.Core.PublicApi.Models.AlertRule.AllDevices is true.",
            "nullable": true
          },
          "user_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The users explicitly notified by the rule (encrypted ids).\r\nEmpty when RevelDigital.Core.PublicApi.Models.AlertRule.AllUsers is true.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Full alert rule model. An alert rule defines the conditions that trigger alerts."
      },
      "AlertRuleRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The name of the alert rule",
            "nullable": true
          },
          "rule_set": {
            "type": "string",
            "description": "The rule set configuration, supplied as a JSON string (the value is serialized JSON,\r\nnot a nested JSON object). A rule set is an array of condition groups; groups are combined\r\nwith logical AND, and the items within each group are combined with logical OR. A rule\r\ntriggers when every group is satisfied.\r\nShape: an array of objects, each with an \"items\" array of { \"type\", \"op\", \"value\" } entries.\r\nFor example: [ { \"items\": [ { \"type\": \"CpuUsage\", \"op\": \"GTE\", \"value\": [90] } ] } ].\r\nItem fields: \"type\" (required, case-sensitive) is one of the supported condition types below;\r\n\"op\" (optional) is the comparison operator EQ, NE, GT, LT, GTE, or LTE and defaults to EQ;\r\n\"value\" (required) is a non-empty array of numbers whose first element is the comparison value.\r\nSupported \"type\" values: TimeOffline (minutes offline), LastUpdate (minutes since last check-in),\r\nMemoryUsage, CpuUsage, DiskUsage (utilization percentage), NoContent (active content count over the period),\r\nBytesTxDay, BytesRxDay, BytesTotalDay (bytes transmitted/received/total for the current day),\r\nBytesTxPeriod, BytesRxPeriod, BytesTotalPeriod (bytes over the period), ClockSkew (clock drift),\r\nDisplayDetected (display presence), BatteryVoltage, BatteryPercentage, and SystemTemperature (hardware sensor readings).\r\nThe rule set is validated on create and update: a malformed JSON string, an empty group, an empty items array,\r\nan unknown \"type\", an unsupported \"op\", or a missing/empty \"value\" is rejected with HTTP 400.\r\nNull or empty is allowed, in which case the rule is simply not evaluated.",
            "nullable": true,
            "example": "[{\"items\":[{\"type\":\"CpuUsage\",\"op\":\"GTE\",\"value\":[90]},{\"type\":\"MemoryUsage\",\"op\":\"GTE\",\"value\":[95]}]}]"
          },
          "is_enabled": {
            "type": "boolean",
            "description": "Indicates whether the alert rule is enabled and will be evaluated.\r\nWhen false, the rule is stored but never triggers alerts. Defaults to enabled when omitted.",
            "nullable": true
          },
          "period": {
            "type": "integer",
            "description": "The look-back / evaluation period, in minutes, used by time-window based conditions\r\nsuch as `NoContent`. Ignored by conditions that read the current value.",
            "format": "int32",
            "nullable": true
          },
          "threshold": {
            "type": "integer",
            "description": "A legacy scalar threshold value retained for backward compatibility. New rules should\r\nexpress thresholds inside RevelDigital.Core.PublicApi.Models.AlertRuleRequest.RuleSet via each item's `value` instead.",
            "format": "int32",
            "nullable": true
          },
          "webhook_url": {
            "type": "string",
            "description": "Optional HTTPS webhook URL that is invoked (HTTP POST) when the rule triggers.\r\nLeave null to notify only through the associated users.",
            "nullable": true
          },
          "all_devices": {
            "type": "boolean",
            "description": "When true, the rule is evaluated against every device in the account and\r\nRevelDigital.Core.PublicApi.Models.AlertRuleRequest.DeviceIds is ignored. When false, only the devices in RevelDigital.Core.PublicApi.Models.AlertRuleRequest.DeviceIds are evaluated.",
            "nullable": true
          },
          "all_users": {
            "type": "boolean",
            "description": "When true, all users in the account are notified and RevelDigital.Core.PublicApi.Models.AlertRuleRequest.UserIds is ignored.\r\nWhen false, only the users in RevelDigital.Core.PublicApi.Models.AlertRuleRequest.UserIds are notified.",
            "nullable": true
          },
          "device_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The devices to associate with the rule. Ignored when all_devices is true.",
            "nullable": true
          },
          "user_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The users to notify (encrypted ids). Ignored when all_users is true.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model used for creating or updating an alert rule (REST). All fields except\r\nRevelDigital.Core.PublicApi.Models.AlertRuleRequest.Name are optional; omitted fields are treated as unset. The\r\nRevelDigital.Core.PublicApi.Models.AlertRuleRequest.RuleSet property documents the full rule set JSON schema."
      },
      "AlertRuleSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The alert rule id (encrypted)",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The name of the alert rule",
            "nullable": true
          },
          "rule_set": {
            "type": "string",
            "description": "The rule set configuration (JSON)",
            "nullable": true
          },
          "is_enabled": {
            "type": "boolean",
            "description": "Indicates if the alert rule is enabled",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Alert rule summary (minimal info included with alerts)"
      },
      "AuditEvent": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "integer",
            "description": "The unique event identifier",
            "format": "int64"
          },
          "timestamp": {
            "type": "string",
            "description": "The date and time the event was recorded",
            "format": "date-time"
          },
          "event_type": {
            "type": "string",
            "description": "The type of event (e.g., API call, login, etc.)",
            "nullable": true
          },
          "user_id": {
            "type": "string",
            "description": "The user ID associated with the event (encrypted)",
            "nullable": true
          },
          "user_name": {
            "type": "string",
            "description": "The name of the user associated with the event",
            "nullable": true
          },
          "account_id": {
            "type": "string",
            "description": "The account ID associated with the event (encrypted)",
            "nullable": true
          },
          "ip_address": {
            "type": "string",
            "description": "The IP address of the client",
            "nullable": true
          },
          "remote_ip_address": {
            "type": "string",
            "description": "The remote IP address",
            "nullable": true
          },
          "user_agent": {
            "type": "string",
            "description": "The user agent string of the client",
            "nullable": true
          },
          "response_code": {
            "type": "string",
            "description": "The HTTP response code",
            "nullable": true
          },
          "duration": {
            "type": "string",
            "description": "The duration of the request",
            "nullable": true
          },
          "http_method": {
            "type": "string",
            "description": "The HTTP method used (GET, POST, PUT, DELETE, etc.)",
            "nullable": true
          },
          "controller_name": {
            "type": "string",
            "description": "The name of the controller that handled the request",
            "nullable": true
          },
          "action_name": {
            "type": "string",
            "description": "The name of the action that was executed",
            "nullable": true
          },
          "app_id": {
            "type": "string",
            "description": "The application identifier",
            "nullable": true
          },
          "geo_location": {
            "type": "string",
            "description": "The geographic location information",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Audit event model representing account activity"
      },
      "BatchCreateRowsRequest": {
        "required": [
          "rows"
        ],
        "type": "object",
        "properties": {
          "rows": {
            "maxItems": 100,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateRowRequest"
            }
          }
        },
        "additionalProperties": false
      },
      "BatchCreateRowsResponse": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchRowResultModel"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchDeleteRowsRequest": {
        "required": [
          "rowIds"
        ],
        "type": "object",
        "properties": {
          "rowIds": {
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false
      },
      "BatchDeleteRowsResponse": {
        "type": "object",
        "properties": {
          "deletedCount": {
            "type": "integer",
            "format": "int32"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BatchRowResultModel"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BatchRowResultModel": {
        "type": "object",
        "properties": {
          "rowId": {
            "type": "string",
            "nullable": true
          },
          "success": {
            "type": "boolean"
          },
          "error": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "Beacon": {
        "type": "object",
        "properties": {
          "distance": {
            "type": "number",
            "description": "The detection distance threshold in meters.\r\nMobile devices within this range will receive beacon notifications.",
            "format": "double",
            "nullable": true
          },
          "calibration": {
            "type": "number",
            "description": "The RSSI calibration value (measured power at 1 meter) used for distance estimation.\r\nThis value is typically negative (e.g., -59 dBm) and device-specific.\r\nAccurate calibration improves proximity zone detection accuracy.",
            "format": "double",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "Contact phone number associated with this beacon location.\r\nDisplayed to users who interact with the beacon via mobile app.",
            "nullable": true
          },
          "emailAddress": {
            "type": "string",
            "description": "Contact email address associated with this beacon location.\r\nDisplayed to users who interact with the beacon via mobile app.",
            "nullable": true
          },
          "website": {
            "type": "string",
            "description": "Website URL associated with this beacon location.\r\nCan be opened by mobile app when user interacts with beacon notification.",
            "nullable": true
          },
          "devices": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of device IDs associated with this beacon configuration.\r\nUsed for grouping multiple devices that share the same beacon identity.",
            "nullable": true
          },
          "rating": {
            "type": "number",
            "description": "Rating value for this beacon location (e.g., customer rating, priority score).\r\nCan be used to rank or filter beacon-triggered content.",
            "format": "double",
            "nullable": true
          },
          "uuid": {
            "type": "string",
            "description": "The iBeacon UUID (Universally Unique Identifier).\r\nA 128-bit identifier typically shared by all beacons in an organization.\r\nFormat: \"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\"",
            "nullable": true
          },
          "major": {
            "type": "string",
            "description": "The iBeacon Major value (0-65535).\r\nTypically used to identify a specific location or venue within an organization.",
            "nullable": true
          },
          "minor": {
            "type": "string",
            "description": "The iBeacon Minor value (0-65535).\r\nTypically used to identify a specific beacon within a location.",
            "nullable": true
          },
          "notification_delay": {
            "type": "integer",
            "description": "Delay in seconds before sending a notification after beacon detection.\r\nPrevents notification spam when users briefly pass by a beacon.\r\nA value of 0 or null means immediate notification.",
            "format": "int32",
            "nullable": true
          },
          "instance_id": {
            "type": "string",
            "description": "The Eddystone Instance ID (6 bytes, 12 hex characters).\r\nIdentifies a specific beacon within an Eddystone namespace.",
            "nullable": true
          },
          "namespace": {
            "type": "string",
            "description": "The Eddystone Namespace ID (10 bytes, 20 hex characters).\r\nTypically derived from a domain name or organization identifier.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents Bluetooth Low Energy (BLE) beacon configuration for a device.\r\nBeacons enable proximity-based interactions, allowing mobile devices to detect nearby digital signage\r\nand trigger location-aware content or notifications."
      },
      "ColumnType": {
        "enum": [
          "string",
          "number",
          "boolean",
          "date",
          "select",
          "media",
          "url",
          "richtext",
          "time",
          "hidden"
        ],
        "type": "string"
      },
      "Command": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          },
          "arg": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "Condition": {
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/ConditionType"
          },
          "operator": {
            "$ref": "#/components/schemas/ConditionOperator"
          },
          "value_1": {
            "type": "string",
            "description": "Value 1. See ConditionType documentation for usage notes.",
            "nullable": true
          },
          "value_2": {
            "type": "string",
            "description": "Value 2. See ConditionType documentation for usage notes.",
            "nullable": true
          },
          "value_3": {
            "type": "string",
            "description": "Value 3. See ConditionType documentation for usage notes.",
            "nullable": true
          },
          "value_4": {
            "type": "string",
            "description": "Value 4. See ConditionType documentation for usage notes.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ConditionOperator": {
        "enum": [
          "And",
          "Or",
          "AndNot",
          "OrNot"
        ],
        "type": "string"
      },
      "ConditionType": {
        "enum": [
          "AfterDate",
          "AfterTime",
          "Always",
          "BeaconActive",
          "BeforeDate",
          "BeforeTime",
          "Command",
          "DateRange",
          "DayOfMonth",
          "DaysOfWeek",
          "DeviceByGroup",
          "DeviceByNestedGroup",
          "DeviceByName",
          "DeviceByTag",
          "DeviceByOrg",
          "Everywhere",
          "GeoLocation",
          "GpsWithinRadius",
          "KeyEvent",
          "MonthOfYear",
          "Motion",
          "Never",
          "Nowhere",
          "PctAdult",
          "PctChild",
          "PctFemale",
          "PctMale",
          "PctSenior",
          "PctYoung",
          "PctYoungAdult",
          "PlaylistByName",
          "PlaylistByTag",
          "SendCommand",
          "SpecificDevice",
          "SpecificPlaylist",
          "SpecificTemplate",
          "SpecificZone",
          "TemplateByName",
          "TemplateByTag",
          "TimeRange",
          "TopicSet",
          "TotalViewersGreaterThan",
          "TotalViewersLessThan",
          "TouchEvent",
          "WeekOfMonth",
          "WeekOfYear"
        ],
        "type": "string",
        "description": "The following enum represents the different types of conditions that can be used in scheduling logic.\r\n\r\nImportant usage notes specific to ConditionType:\r\n\r\n- ConditionType: \"TimeRange\"\r\n  Value1: \"01/01/1970 12:00:00 AM\" # Start time. Starts at this time. Date/time format: \"MM/dd/yyyy hh:mm:ss aa\"\r\n  Value2: \"01/01/1970 12:00:00 AM\" # End time. Stops at this time. Date/time format: \"MM/dd/yyyy hh:mm:ss aa\"\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"TopicSet\"\r\n  Value1: \"sports,news,weather\" # Comma separted list of topics\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"TotalViewersGreaterThan\"\r\n  Value1: \"50\"\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"TotalViewersLessThan\"\r\n  Value1: \"100\"\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"TouchEvent\"\r\n  Value1: \"tap\"\r\n  Value2: \"screen1\"\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"WeekOfMonth\"\r\n  Value1: \"2\"\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"WeekOfYear\"\r\n  Value1: \"25\"\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"GpsWithinRadius\"\r\n  Value1: \"40.7128\"\r\n  Value2: \"-74.0060\"\r\n  Value3: \"50\"\r\n  Value4: \"miles\"\r\n- ConditionType: \"KeyEvent\"\r\n  Value1: \"ENTER\"\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"MonthOfYear\"\r\n  Value1: \"12\"\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"Motion\"\r\n  Value1: \"detected\"\r\n  Value2: \"5\"\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"Never\"\r\n  Value1: null\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"PctAdult\"\r\n  Value1: \"60\"\r\n  Value2: \">=\"\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"PctChild\"\r\n  Value1: \"25\"\r\n  Value2: \"<=\"\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"PctFemale\"\r\n  Value1: \"40\"\r\n  Value2: \">=\"\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"PctMale\"\r\n  Value1: \"60\"\r\n  Value2: \"<=\"\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"PctSenior\"\r\n  Value1: \"15\"\r\n  Value2: \">=\"\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"PctYoung\"\r\n  Value1: \"30\"\r\n  Value2: \"<=\"\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"PctYoungAdult\"\r\n  Value1: \"35\"\r\n  Value2: \">=\"\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"AfterDate\"\r\n  Value1: \"01/01/1970 12:00:00 AM\" # Date/time format: \"MM/dd/yyyy hh:mm:ss aa\"\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"AfterTime\"\r\n  Value1: \"01/01/1970 12:00:00 AM\" # Date/time format: \"MM/dd/yyyy hh:mm:ss aa\"\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"Always\"\r\n  Value1: null\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"BeaconActive\"\r\n  Value1: \"Beacon Name\" # Name of the beacon\r\n  Value2: \"UUID / Namespace\" # UUID or Namespace identifier\r\n  Value3: \"Major / Instance\" # Major ID or Instance identifier\r\n  Value4: \"Minor\" # Minor ID\r\n- ConditionType: \"BeforeDate\"\r\n  Value1: \"01/01/1970 12:00:00 AM\" # Date/time format: \"MM/dd/yyyy hh:mm:ss aa\"\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"BeforeTime\"\r\n  Value1: \"01/01/1970 12:00:00 AM\" # Date/time format: \"MM/dd/yyyy hh:mm:ss aa\"\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"Command\"\r\n  Value1: \"Command Name\"\r\n  Value2: \"Command Arg\"\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"DateRange\"\r\n  Value1: \"01/01/1970 12:00:00 AM\" # Start date. Starts ON this date. Date/time format: \"MM/dd/yyyy hh:mm:ss aa\"\r\n  Value2: \"01/01/1970 12:00:00 AM\" # End date. Stops AFTER this date. Date/time format: \"MM/dd/yyyy hh:mm:ss aa\"\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"DayOfMonth\"\r\n  Value1: \"15\"\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"DaysOfWeek\"\r\n  Value1: \"10\" # Integer Bitfield starting with Sunday as the least significant bit\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"DeviceByGroup\" # Selects all devices in a group by the groups unique identifier\r\n  Value1: 0 # Unique device group ID\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"DeviceByName\" # Selects a device by its name. Supports regular expressions for advanced matching\r\n  Value1: \"Device Name\" # Supports regular expressions\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"DeviceByNestedGroup\" # Selects all devices in a group by the groups unique identifier. Includes all devices in this group and all nested groups\r\n  Value1: 0 # Unique device group ID\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"DeviceByOrg\" # Selects all devices in an organization\r\n  Value1: 0 # Unique organization ID\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"DeviceByTag\" # Selects devices by their associated tags\r\n  Value1: \"critical_infrastructure\" # Newline separted list of tags\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"Everywhere\"\r\n  Value1: null\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"GeoLocation\"\r\n  Value1: \"37.7749\" # Latitude of the location\r\n  Value2: \"-122.4194\" # Longitude of the location\r\n  Value3: \"50\" # Distance in miles from geolocation\"\r\n  Value4: \"123 5th St. N\" # Street address of the location\r\n- ConditionType: \"Nowhere\"\r\n  Value1: null\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null\r\n- ConditionType: \"SpecificDevice\"\r\n  Value1: 0 # Unique device ID\r\n  Value2: null\r\n  Value3: null\r\n  Value4: null"
      },
      "CreateDataTableRequest": {
        "required": [
          "columns",
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 100,
            "minLength": 0,
            "type": "string"
          },
          "description": {
            "maxLength": 500,
            "minLength": 0,
            "type": "string",
            "nullable": true
          },
          "groupId": {
            "type": "string",
            "nullable": true
          },
          "columns": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataTableColumnModel"
            }
          },
          "cacheTtlSeconds": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateRowRequest": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "additionalProperties": { },
            "description": "Free-form JSON object keyed by column `key`; each value is a raw JSON scalar, object, or `media` object."
          }
        },
        "additionalProperties": false
      },
      "DataTableColumnModel": {
        "required": [
          "key",
          "name",
          "type"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "minLength": 1,
            "type": "string"
          },
          "key": {
            "minLength": 1,
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/ColumnType"
          },
          "required": {
            "type": "boolean"
          },
          "sortable": {
            "type": "boolean"
          },
          "locked": {
            "type": "boolean"
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "default": {
            "description": "Any JSON value (string, number, boolean, object, or array).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "DataTableDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "columns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataTableColumnModel"
            },
            "nullable": true
          },
          "groupId": {
            "type": "string",
            "nullable": true
          },
          "rowCount": {
            "type": "integer",
            "format": "int32"
          },
          "cacheTtlSeconds": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "DataTableListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataTableSummary"
            },
            "nullable": true
          },
          "continuationToken": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "DataTableRowModel": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "data": {
            "type": "object",
            "additionalProperties": { },
            "description": "Stored row data as a JSON object keyed by column `key`. Values follow each\r\ncolumn's `ColumnType` rules: STRING/RICHTEXT/HIDDEN/SELECT/URL/DATE/TIME are\r\nJSON strings, NUMBER is a JSON number, BOOLEAN is JSON true/false, and MEDIA is\r\nalways a normalized object `{ url, thumbnailUrl, name, mimeType, mediaId? }`\r\n(id and id-object input forms are expanded server-side at write time).",
            "nullable": true
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "eTag": {
            "type": "string",
            "description": "Optimistic concurrency token. To ensure the row hasn't changed since you read it,\r\nsend this value back as the `If-Match` request header on the REST\r\n`updateDataTableRow` (HTTP `PUT`) call, or as the `eTag` input field on\r\nthe GraphQL `updateDataTableRow` mutation. A stale token results in\r\n`409 Conflict` (REST) or a mutation error (GraphQL). Note: the REST endpoint does\r\nnot read an `eTag` body property — it uses the `If-Match` header.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "DataTableSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "columnCount": {
            "type": "integer",
            "format": "int32"
          },
          "rowCount": {
            "type": "integer",
            "format": "int32"
          },
          "groupId": {
            "type": "string",
            "nullable": true
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "Device": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The device id",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The device name",
            "nullable": true
          },
          "group_name": {
            "type": "string",
            "description": "The group name",
            "nullable": true
          },
          "group_id": {
            "type": "string",
            "description": "The group id",
            "nullable": true
          },
          "tags": {
            "type": "string",
            "description": "Tags associated with this device",
            "nullable": true
          },
          "device_type": {
            "$ref": "#/components/schemas/DeviceType"
          },
          "entered_service": {
            "type": "string",
            "description": "The date the device was registered",
            "format": "date-time",
            "nullable": true
          },
          "last_service": {
            "type": "string",
            "description": "The last service date",
            "format": "date-time",
            "nullable": true
          },
          "timezone": {
            "type": "string",
            "description": "The timezone of the device",
            "nullable": true
          },
          "language_code": {
            "type": "string",
            "description": "The language code of the device",
            "nullable": true
          },
          "last_update": {
            "type": "string",
            "description": "The timestamp of the last content sync with the server",
            "format": "date-time",
            "nullable": true
          },
          "location": {
            "$ref": "#/components/schemas/Location"
          },
          "ping_data": {
            "$ref": "#/components/schemas/PingData"
          },
          "registration_key": {
            "type": "string",
            "description": "The device registration key",
            "nullable": true
          },
          "encrypted_registration_key": {
            "type": "string",
            "description": "The encrypted registration key",
            "nullable": true
          },
          "mac_address": {
            "type": "string",
            "description": "The device MAC address, if applicable",
            "nullable": true
          },
          "beacon": {
            "$ref": "#/components/schemas/Beacon"
          },
          "service_level": {
            "type": "string",
            "description": "The device service level",
            "nullable": true
          },
          "in_sync": {
            "type": "boolean",
            "description": "Is the device content in sync with server"
          },
          "serial_number": {
            "type": "string",
            "description": "The device serial number",
            "nullable": true
          },
          "model": {
            "type": "string",
            "description": "The device hardware model",
            "nullable": true
          },
          "deactivated": {
            "type": "boolean",
            "description": "Is the device deactivated",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "description": "The device notes",
            "nullable": true
          },
          "is_online": {
            "type": "boolean",
            "description": "Is the device currently online.\r\nA device is considered online if it has a timestamp within the last 5 minutes"
          },
          "screen_orientation": {
            "type": "integer",
            "description": "Degrees of screen rotation. One of 0, 90, 180 or 270.\r\nA null value means the orientation is not stated.",
            "format": "int32",
            "nullable": true
          },
          "is_audio_enabled": {
            "type": "boolean",
            "description": "Whether the screen can play audible audio.\r\nA null value means this is not stated, and is never treated as false.",
            "nullable": true
          },
          "is_outdoor": {
            "type": "boolean",
            "description": "Whether the screen is deployed outdoors.\r\nA null value means this is not stated, and is never treated as false.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a digital signage player device in the RevelDigital platform.\r\nA device is a registered hardware unit that displays content according to assigned schedules and templates."
      },
      "DeviceCommand": {
        "type": "object",
        "properties": {
          "deviceId": {
            "type": "string",
            "nullable": true
          },
          "commands": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Command"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "DeviceJsonPatchDocument": {
        "type": "object",
        "properties": {
          "operations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DeviceOperation"
            },
            "nullable": true,
            "readOnly": true
          },
          "contractResolver": {
            "$ref": "#/components/schemas/IContractResolver"
          }
        },
        "additionalProperties": false
      },
      "DeviceOperation": {
        "type": "object",
        "properties": {
          "operationType": {
            "$ref": "#/components/schemas/OperationType"
          },
          "path": {
            "type": "string",
            "nullable": true
          },
          "op": {
            "type": "string",
            "nullable": true
          },
          "from": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "DeviceRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The device name",
            "nullable": true
          },
          "tags": {
            "type": "string",
            "description": "Tags associated with this device",
            "nullable": true
          },
          "timeZone": {
            "type": "string",
            "description": "The timezone of the device",
            "nullable": true
          },
          "language_code": {
            "type": "string",
            "description": "The language code of the device",
            "nullable": true
          },
          "group_id": {
            "type": "string",
            "description": "The group id",
            "nullable": true
          },
          "last_service": {
            "type": "string",
            "description": "The last service date",
            "format": "date-time",
            "nullable": true
          },
          "mac_address": {
            "type": "string",
            "description": "The MAC address of this device, is applicable",
            "nullable": true
          },
          "location": {
            "$ref": "#/components/schemas/Location"
          },
          "beacon": {
            "$ref": "#/components/schemas/Beacon"
          },
          "notes": {
            "type": "string",
            "description": "Free-form notes associated with this device.",
            "nullable": true
          },
          "serial_number": {
            "type": "string",
            "description": "The device serial number",
            "nullable": true
          },
          "screen_orientation": {
            "type": "integer",
            "description": "Degrees of screen rotation. One of 0, 90, 180 or 270.\r\nA null value means the orientation is not stated.",
            "format": "int32",
            "nullable": true
          },
          "is_audio_enabled": {
            "type": "boolean",
            "description": "Whether the screen can play audible audio. This is distinct from the configured volume:\r\na screen may have a volume set but no speakers, or sit where audio is not permitted.\r\nA null value means this is not stated, and is never treated as false.",
            "nullable": true
          },
          "is_outdoor": {
            "type": "boolean",
            "description": "Whether the screen is deployed outdoors. A null value means this is not stated, and is\r\nnever treated as false.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model used for creating and updating devices in the RevelDigital platform.\r\nContains the mutable properties that can be set when registering or modifying a device."
      },
      "DeviceType": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The unique identifier for the device type.\r\nThis is typically a string-based key used to reference the device type across the platform.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The display name of the device type.\r\nExamples include model names or product line identifiers (e.g., \"BrightSign HD\", \"Samsung Tizen\", \"LG webOS\").",
            "nullable": true
          },
          "manufacturer": {
            "type": "string",
            "description": "The manufacturer or vendor of the device type.\r\nExamples include \"BrightSign\", \"Samsung\", \"LG\", \"Android\", etc.",
            "nullable": true
          },
          "device_caps": {
            "type": "integer",
            "description": "A bitmask representing the capabilities supported by this device type.\r\nNull indicates capabilities have not been defined for this device type.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a device type classification in the RevelDigital digital signage platform.\r\nThis DTO defines the hardware type and capabilities of a digital signage player device.\r\nDevice types are used to categorize devices by their manufacturer and supported features."
      },
      "Event": {
        "type": "object",
        "properties": {
          "session_id": {
            "type": "string",
            "nullable": true
          },
          "event_name": {
            "type": "string",
            "nullable": true
          },
          "properties": {
            "type": "object",
            "additionalProperties": {
              "nullable": true
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "FormatType": {
        "enum": [
          "XML",
          "CSV",
          "IMAGE",
          "PDF",
          "EXCEL",
          "WORD",
          "HTML",
          "MHTML"
        ],
        "type": "string"
      },
      "Group": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The group id",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The group name",
            "nullable": true
          },
          "parent_id": {
            "type": "string",
            "description": "The parent group id",
            "nullable": true
          },
          "count": {
            "type": "integer",
            "description": "The number of items in this group",
            "format": "int32",
            "nullable": true
          },
          "level": {
            "type": "integer",
            "description": "The nested level of this group",
            "format": "int32",
            "nullable": true
          },
          "family": {
            "type": "integer",
            "description": "The family id",
            "format": "int64",
            "nullable": true
          },
          "organization_count": {
            "type": "integer",
            "description": "The organization count",
            "format": "int32",
            "nullable": true
          },
          "children": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Group"
            },
            "description": "The children groups",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents an organizational folder/group for categorizing resources in the RevelDigital platform.\r\nGroups form a hierarchical tree structure for organizing devices, media, playlists, templates, and schedules."
      },
      "GroupRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The group name",
            "nullable": true
          },
          "parentId": {
            "type": "string",
            "description": "The parent group Id (optional)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model for creating a new group."
      },
      "IContractResolver": {
        "type": "object",
        "additionalProperties": false
      },
      "ImportRowErrorModel": {
        "type": "object",
        "properties": {
          "lineNumber": {
            "type": "integer",
            "format": "int32"
          },
          "error": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ImportRowsResponse": {
        "type": "object",
        "properties": {
          "successCount": {
            "type": "integer",
            "format": "int32"
          },
          "errorCount": {
            "type": "integer",
            "format": "int32"
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ImportRowErrorModel"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "IntervalType": {
        "enum": [
          "Minute",
          "Hour",
          "Day",
          "Month"
        ],
        "type": "string",
        "description": "Specifies the time interval granularity for aggregating analytics data.\r\nUsed with reporting and analytics endpoints to control data grouping."
      },
      "JsonPatchDocument": {
        "type": "array",
        "items": {
          "$ref": "#/components/schemas/Operation"
        },
        "description": "Array of operations to perform"
      },
      "Location": {
        "type": "object",
        "properties": {
          "city": {
            "type": "string",
            "description": "City",
            "nullable": true
          },
          "state": {
            "type": "string",
            "description": "State",
            "nullable": true
          },
          "county": {
            "type": "string",
            "description": "County",
            "nullable": true
          },
          "country": {
            "type": "string",
            "description": "Country",
            "nullable": true
          },
          "postal_code": {
            "type": "string",
            "description": "Postal code",
            "nullable": true
          },
          "address": {
            "type": "string",
            "description": "Address",
            "nullable": true
          },
          "latitude": {
            "type": "number",
            "description": "Latitude",
            "format": "double",
            "nullable": true
          },
          "longitude": {
            "type": "number",
            "description": "Longitude",
            "format": "double",
            "nullable": true
          },
          "venue_id": {
            "type": "integer",
            "description": "The OpenOOH venue type id describing how this screen is deployed, e.g. 10101 for an\r\nairport arrival hall. Used to build OpenRTB 2.6 bid requests.\r\n\r\nThis replaces the deprecated \"venue:{id}\" device tag. This field is the only supported\r\nway to read or set the venue; venue tags are no longer interpreted. A null value means\r\nthe venue is not stated, and setting null explicitly clears it.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "LoopPolicyType": {
        "enum": [
          "Default",
          "OverSaturate2x",
          "OverSaturate3x",
          "OverSaturate4x",
          "OverSaturate5x",
          "Random",
          "UnderSaturate2x",
          "UnderSaturate3x",
          "UnderSaturate4x",
          "UnderSaturate5x",
          "Prefill",
          "Postfill",
          "Spreadfill"
        ],
        "type": "string",
        "description": "Loop policy type determines how a source is to generatively positioned within a loop.\r\nIMPORTANT: Playlist duration must be set for this to take effect. If no playlist duration is specified, then source loop policy should not be assigned."
      },
      "Media": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The media name",
            "nullable": true
          },
          "group_id": {
            "type": "string",
            "description": "The group id",
            "nullable": true
          },
          "tags": {
            "type": "string",
            "description": "The tags associated with this media",
            "nullable": true
          },
          "advertiser_id": {
            "type": "string",
            "description": "The advertiser id. Optional",
            "nullable": true
          },
          "is_shared": {
            "type": "boolean",
            "description": "Is this media shared with other accounts",
            "nullable": true
          },
          "start_date": {
            "type": "string",
            "description": "The start date for this media",
            "format": "date-time",
            "nullable": true
          },
          "end_date": {
            "type": "string",
            "description": "The end date for this media",
            "format": "date-time",
            "nullable": true
          },
          "id": {
            "type": "string",
            "description": "The media id",
            "nullable": true
          },
          "group_name": {
            "type": "string",
            "description": "The group name",
            "nullable": true
          },
          "mime_type": {
            "type": "string",
            "description": "The MIME type for this media",
            "nullable": true
          },
          "file_size": {
            "type": "integer",
            "description": "The file size in bytes",
            "format": "int32"
          },
          "file_name": {
            "type": "string",
            "description": "The file name",
            "nullable": true
          },
          "file_url": {
            "type": "string",
            "description": "The file URL",
            "nullable": true
          },
          "thumbnail_url": {
            "type": "string",
            "description": "The thumbnail URL",
            "nullable": true
          },
          "uploaded_on": {
            "type": "string",
            "description": "The date the media was uploaded",
            "format": "date-time",
            "nullable": true
          },
          "uploaded_by_id": {
            "type": "string",
            "description": "The user id that uploaded the media",
            "nullable": true
          },
          "sha_512": {
            "type": "string",
            "description": "The SHA512 hash of the media file",
            "nullable": true
          },
          "width": {
            "type": "integer",
            "description": "The width of the media",
            "format": "int32",
            "nullable": true
          },
          "height": {
            "type": "integer",
            "description": "The height of the media",
            "format": "int32",
            "nullable": true
          },
          "is_approved": {
            "type": "boolean",
            "description": "Approval state. True = approved for playback, false = declined, null = pending review.",
            "nullable": true
          },
          "approved_on": {
            "type": "string",
            "description": "Timestamp the media was approved, if applicable.",
            "format": "date-time",
            "nullable": true
          },
          "declined_on": {
            "type": "string",
            "description": "Timestamp the media was declined, if applicable.",
            "format": "date-time",
            "nullable": true
          },
          "declined_reason": {
            "type": "string",
            "description": "Reason recorded when the media was declined, if any.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a media asset (image, video, audio, document) in the RevelDigital content library.\r\nMedia files are uploaded to the platform and referenced by playlists and templates for playback on devices."
      },
      "MediaRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The media name",
            "nullable": true
          },
          "group_id": {
            "type": "string",
            "description": "The group id",
            "nullable": true
          },
          "tags": {
            "type": "string",
            "description": "The tags associated with this media",
            "nullable": true
          },
          "advertiser_id": {
            "type": "string",
            "description": "The advertiser id. Optional",
            "nullable": true
          },
          "is_shared": {
            "type": "boolean",
            "description": "Is this media shared with other accounts",
            "nullable": true
          },
          "start_date": {
            "type": "string",
            "description": "The start date for this media",
            "format": "date-time",
            "nullable": true
          },
          "end_date": {
            "type": "string",
            "description": "The end date for this media",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Media request model. Used for creating and updating media"
      },
      "MediaRequestJsonPatchDocument": {
        "type": "object",
        "properties": {
          "operations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MediaRequestOperation"
            },
            "nullable": true,
            "readOnly": true
          },
          "contractResolver": {
            "$ref": "#/components/schemas/IContractResolver"
          }
        },
        "additionalProperties": false
      },
      "MediaRequestOperation": {
        "type": "object",
        "properties": {
          "operationType": {
            "$ref": "#/components/schemas/OperationType"
          },
          "path": {
            "type": "string",
            "nullable": true
          },
          "op": {
            "type": "string",
            "nullable": true
          },
          "from": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "MediaUploadRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The file name of the asset to upload, including extension (e.g. `myapp.webapp`).\r\nThe extension determines the resulting media type, so preserve `.webapp` for webapp bundles.",
            "nullable": true
          },
          "group_id": {
            "type": "string",
            "description": "Optional media group id the finalized media will be placed in. When omitted the\r\naccount's root media group is used.",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional tags applied to the finalized media (stored newline-delimited on the media record).",
            "nullable": true
          },
          "content_type": {
            "type": "string",
            "description": "Optional content type the client will send on the S3 PUT. Defaults to `application/zip`\r\nfor `.webapp` bundles, otherwise the type inferred from the file extension.\r\nThe value is pinned into the presigned signature and the client MUST send the same header.",
            "nullable": true
          },
          "advertiser_id": {
            "type": "string",
            "description": "Optional advertiser/user id the finalized media is attributed to.",
            "nullable": true
          },
          "is_shared": {
            "type": "boolean",
            "description": "Optional flag marking the finalized media as shared with other accounts.",
            "nullable": true
          },
          "size": {
            "type": "integer",
            "description": "Optional declared object size in bytes. When supplied it is validated against the\r\nconfigured maximum up front; the real size is always re-validated at finalize.",
            "format": "int64",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request body for creating a direct-to-S3 upload slot via `POST /media/uploads`."
      },
      "MediaUploadResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The opaque upload slot id. Use it to finalize (`POST /media/uploads/{id}/finalize`)\r\nor to query status (`GET /media/uploads/{id}`).",
            "nullable": true
          },
          "upload_url": {
            "type": "string",
            "description": "The presigned S3 URL the client uploads the raw bytes to.",
            "nullable": true
          },
          "method": {
            "type": "string",
            "description": "The HTTP method to use against RevelDigital.Core.PublicApi.Models.MediaUploadResponse.UploadUrl. Always `PUT`.",
            "nullable": true
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "nullable": true
            },
            "description": "The exact headers the client MUST send on the upload request (at minimum `Content-Type`).",
            "nullable": true
          },
          "key": {
            "type": "string",
            "description": "The S3 object key the bytes are written to. Scoped to the authenticated account.",
            "nullable": true
          },
          "expires_at": {
            "type": "string",
            "description": "The UTC time the presigned URL expires (ISO-8601).",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Response returned from `POST /media/uploads` describing the presigned S3 PUT slot."
      },
      "MediaUploadStatus": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The upload slot id.",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "The current state: `pending` (awaiting upload), `uploaded` (object present, not finalized),\r\nor `completed` (media record created).",
            "nullable": true
          },
          "key": {
            "type": "string",
            "description": "The S3 object key for this slot.",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "description": "When the slot was created (UTC).",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "description": "When the presigned URL expires (UTC).",
            "format": "date-time"
          },
          "media_id": {
            "type": "string",
            "description": "The created media id once the slot has been finalized; otherwise null.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Status of an upload slot returned from `GET /media/uploads/{id}`."
      },
      "Module": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Module/zone unique identifier",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Module/zone name",
            "nullable": true
          },
          "type": {
            "type": "string",
            "description": "Module/zone type (e.g., 'Playlist', 'Clock', 'Weather', 'Ticker', 'Web')",
            "nullable": true
          },
          "left": {
            "type": "integer",
            "description": "Left position in pixels from the top-left corner of the template",
            "format": "int32",
            "nullable": true
          },
          "top": {
            "type": "integer",
            "description": "Top position in pixels from the top-left corner of the template",
            "format": "int32",
            "nullable": true
          },
          "width": {
            "type": "integer",
            "description": "Width of the module/zone in pixels",
            "format": "int32",
            "nullable": true
          },
          "height": {
            "type": "integer",
            "description": "Height of the module/zone in pixels",
            "format": "int32",
            "nullable": true
          },
          "playlist_id": {
            "type": "string",
            "description": "Playlist ID assigned to this module/zone.\r\nDetermines what content is displayed in this area of the screen.",
            "nullable": true
          },
          "sequence": {
            "type": "integer",
            "description": "Sequence or Z-order for overlapping modules/zones.\r\nHigher values appear in front of lower values.",
            "format": "int32",
            "nullable": true
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ModuleOption"
            },
            "description": "Module/zone configuration options (key-value pairs).\r\nUsed to store type-specific settings like timezone for Clock zones, location for Weather zones, etc.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a module (also called a zone or region) within a template layout.\r\nModules/zones define rectangular areas on screen where content from playlists is displayed.\r\nThe terms \"module\" and \"zone\" are used interchangeably throughout the API."
      },
      "ModuleOption": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Module/zone option unique identifier",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Option name/key (e.g., 'timezone', 'location', 'refresh_interval')",
            "nullable": true
          },
          "value": {
            "type": "string",
            "description": "Option value (stored as string, parse as needed for the specific option)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a configuration option for a module/zone (key-value pair).\r\nModule/zone options store settings specific to each module/zone type."
      },
      "ModuleOptionRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Option name/key (e.g., 'timezone', 'location', 'url')",
            "nullable": true
          },
          "value": {
            "type": "string",
            "description": "Option value (string representation that will be parsed based on the option type)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model for creating or updating a module/zone option.\r\nUsed to set configuration values for specific module/zone types."
      },
      "ModuleOptionRequestJsonPatchDocument": {
        "type": "object",
        "properties": {
          "operations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ModuleOptionRequestOperation"
            },
            "nullable": true,
            "readOnly": true
          },
          "contractResolver": {
            "$ref": "#/components/schemas/IContractResolver"
          }
        },
        "additionalProperties": false
      },
      "ModuleOptionRequestOperation": {
        "type": "object",
        "properties": {
          "operationType": {
            "$ref": "#/components/schemas/OperationType"
          },
          "path": {
            "type": "string",
            "nullable": true
          },
          "op": {
            "type": "string",
            "nullable": true
          },
          "from": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ModuleRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Module/zone name (descriptive identifier)",
            "nullable": true
          },
          "type": {
            "type": "string",
            "description": "Module/zone type (e.g., 'Playlist', 'Clock', 'Weather', 'Ticker', 'Web')",
            "nullable": true
          },
          "left": {
            "type": "integer",
            "description": "Left position",
            "format": "int32",
            "nullable": true
          },
          "top": {
            "type": "integer",
            "description": "Top position",
            "format": "int32",
            "nullable": true
          },
          "width": {
            "type": "integer",
            "description": "Width",
            "format": "int32",
            "nullable": true
          },
          "height": {
            "type": "integer",
            "description": "Height",
            "format": "int32",
            "nullable": true
          },
          "playlist_id": {
            "type": "string",
            "description": "Playlist assigned to this module",
            "nullable": true
          },
          "sequence": {
            "type": "integer",
            "description": "Sequence or Z-Order",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model for creating or updating a module/zone within a template.\r\nUsed for partial updates via PATCH or full updates via PUT.\r\nDefines the properties and configuration of a content area on the screen."
      },
      "ModuleRequestJsonPatchDocument": {
        "type": "object",
        "properties": {
          "operations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ModuleRequestOperation"
            },
            "nullable": true,
            "readOnly": true
          },
          "contractResolver": {
            "$ref": "#/components/schemas/IContractResolver"
          }
        },
        "additionalProperties": false
      },
      "ModuleRequestOperation": {
        "type": "object",
        "properties": {
          "operationType": {
            "$ref": "#/components/schemas/OperationType"
          },
          "path": {
            "type": "string",
            "nullable": true
          },
          "op": {
            "type": "string",
            "nullable": true
          },
          "from": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "Operation": {
        "type": "object",
        "properties": {
          "op": {
            "type": "string"
          },
          "value": {
            "type": "object"
          },
          "path": {
            "type": "string"
          }
        }
      },
      "OperationType": {
        "enum": [
          "Add",
          "Remove",
          "Replace",
          "Move",
          "Copy",
          "Test",
          "Invalid"
        ],
        "type": "string"
      },
      "Organization": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The organization id",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The organization name",
            "nullable": true
          },
          "address_1": {
            "type": "string",
            "description": "Address line 1",
            "nullable": true
          },
          "address_2": {
            "type": "string",
            "description": "Address line 2",
            "nullable": true
          },
          "city": {
            "type": "string",
            "description": "The city",
            "nullable": true
          },
          "state": {
            "type": "string",
            "description": "The state",
            "nullable": true
          },
          "postal_code": {
            "type": "string",
            "description": "The postal code",
            "nullable": true
          },
          "country": {
            "type": "string",
            "description": "The country",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "The phone number",
            "nullable": true
          },
          "fax": {
            "type": "string",
            "description": "The fax number",
            "nullable": true
          },
          "timeZone": {
            "type": "string",
            "description": "The time zone",
            "nullable": true
          },
          "language_code": {
            "type": "string",
            "description": "The language code",
            "nullable": true
          },
          "users": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/User"
            },
            "description": "The users assigned to this organization",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents an organization (reseller/partner) in the RevelDigital platform.\r\nOrganizations are parent entities that manage multiple RevelDigital.Core.PublicApi.Models.Accounts in multi-tenant scenarios."
      },
      "PingData": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Ping type",
            "nullable": true
          },
          "snap": {
            "type": "string",
            "description": "Snapshot (screenshot) of live player content",
            "format": "byte",
            "nullable": true
          },
          "player_version": {
            "type": "string",
            "description": "Player version number",
            "nullable": true
          },
          "os_version": {
            "type": "string",
            "description": "Player OS version",
            "nullable": true
          },
          "cpu_usage": {
            "type": "number",
            "description": "CPU usage (percentage)\r\nValue range [0, 100]",
            "format": "float"
          },
          "memory_usage": {
            "type": "number",
            "description": "Memory usage (percentage)\r\nValue range [0, 100]",
            "format": "float"
          },
          "mac_address": {
            "type": "string",
            "description": "MAC address of primary player network interface",
            "nullable": true
          },
          "disk_usage": {
            "type": "number",
            "description": "Disk usage (percentage)\r\nValue range [0, 100]",
            "format": "float"
          },
          "timestamp": {
            "type": "string",
            "description": "Timestamp of this ping.\r\nDevice is considered offline if this timestamp is older than 10 minutes",
            "format": "date-time"
          },
          "bytes_received": {
            "type": "integer",
            "description": "Bytes recieved by this player",
            "format": "int64"
          },
          "transfer_rate": {
            "type": "integer",
            "description": "Current transfer rate over the primary network interface",
            "format": "int64"
          },
          "ip_address": {
            "type": "string",
            "description": "IP address of the primary network interface",
            "nullable": true
          },
          "latitude": {
            "type": "number",
            "description": "Current location of the player (latitude)",
            "format": "double",
            "nullable": true
          },
          "longitude": {
            "type": "number",
            "description": "Current location of the player (longitude)",
            "format": "double",
            "nullable": true
          },
          "current_schedule": {
            "type": "string",
            "description": "Currently running schedule",
            "nullable": true
          },
          "uptime": {
            "type": "integer",
            "description": "Current uptime of the player (milliseconds)",
            "format": "int64",
            "nullable": true
          },
          "external_ip_address": {
            "type": "string",
            "description": "IP address as seen by the server for this device",
            "nullable": true
          },
          "download_pct_complete": {
            "type": "integer",
            "description": "Package download progress (percentage)",
            "format": "int64",
            "nullable": true
          },
          "meta": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "nullable": true
            },
            "description": "Dictionary of meta data",
            "nullable": true
          },
          "cpu_temperature": {
            "type": "number",
            "description": "Current CPU temperature",
            "format": "float",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "Playlist": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The playlist id",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The playlist name",
            "nullable": true
          },
          "group_name": {
            "type": "string",
            "description": "The group name",
            "nullable": true
          },
          "group_id": {
            "type": "string",
            "description": "The group id",
            "nullable": true
          },
          "tags": {
            "type": "string",
            "description": "The tags associated with this playlist",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/PlaylistType"
          },
          "duration": {
            "type": "integer",
            "description": "User-defined fixed duration for this playlist in seconds. Used in conjunction with loop policy\r\nto control how sources are looped or truncated to fit within this fixed duration.\r\nThis is different from CalculatedDuration which represents the sum of all source durations.",
            "format": "int32",
            "nullable": true
          },
          "calculated_duration": {
            "type": "integer",
            "description": "The total calculated duration of the playlist in seconds, based on the sum of all source intervals.\r\nThis is a read-only property computed from individual source durations and cannot be updated via PUT/POST.",
            "format": "int32",
            "nullable": true
          },
          "is_random_start": {
            "type": "boolean",
            "description": "Randomize the order of the playlist",
            "nullable": true
          },
          "created_on": {
            "type": "string",
            "description": "The date the playlist was created",
            "format": "date-time",
            "nullable": true
          },
          "created_by_id": {
            "type": "string",
            "description": "The user id that created the playlist",
            "nullable": true
          },
          "modified_on": {
            "type": "string",
            "description": "The date the playlist was last modified",
            "format": "date-time",
            "nullable": true
          },
          "modified_by_id": {
            "type": "string",
            "description": "The user id that last modified the playlist",
            "nullable": true
          },
          "sources": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Source"
            },
            "description": "The sources associated with this playlist",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a playlist containing an ordered collection of content sources for playback on digital signage devices.\r\nPlaylists define what content plays and in what order within a template module or schedule."
      },
      "PlaylistJsonPatchDocument": {
        "type": "object",
        "properties": {
          "operations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlaylistOperation"
            },
            "nullable": true,
            "readOnly": true
          },
          "contractResolver": {
            "$ref": "#/components/schemas/IContractResolver"
          }
        },
        "additionalProperties": false
      },
      "PlaylistOperation": {
        "type": "object",
        "properties": {
          "operationType": {
            "$ref": "#/components/schemas/OperationType"
          },
          "path": {
            "type": "string",
            "nullable": true
          },
          "op": {
            "type": "string",
            "nullable": true
          },
          "from": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PlaylistType": {
        "enum": [
          "Multimedia",
          "Slideshow",
          "Template",
          "Marquee"
        ],
        "type": "string"
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": { }
      },
      "ReorderRowsRequest": {
        "required": [
          "rowIds"
        ],
        "type": "object",
        "properties": {
          "rowIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false
      },
      "Report": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The unique identifier for the report.\r\nCorresponds to the SSRS report path/name.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The display name of the report shown in the UI.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "A description of what the report contains and its purpose.",
            "nullable": true
          },
          "parameters": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReportParameter"
            },
            "description": "The list of parameters required or optional for generating this report.\r\nParameters define filters such as date range, device selection, or grouping options.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a report definition available in the RevelDigital reporting system.\r\nReports provide analytics and insights on device activity, content playback, and network health."
      },
      "ReportExportPostBody": {
        "required": [
          "report_id"
        ],
        "type": "object",
        "properties": {
          "report_id": {
            "type": "string",
            "description": "Report name",
            "nullable": true
          },
          "format": {
            "$ref": "#/components/schemas/FormatType"
          },
          "activity_type": {
            "type": "string",
            "description": "Activity type",
            "nullable": true
          },
          "interval_type": {
            "$ref": "#/components/schemas/IntervalType"
          },
          "start_date": {
            "type": "string",
            "description": "Report start date.\r\n\r\nProvide in ISO 8601 format: YYYY-MM-DDThh:mm:ssZ",
            "format": "date-time",
            "nullable": true
          },
          "end_date": {
            "type": "string",
            "description": "Report end date.\r\n\r\nProvide in ISO 8601 format: YYYY-MM-DDThh:mm:ssZ",
            "format": "date-time",
            "nullable": true
          },
          "start_time": {
            "type": "string",
            "description": "Report start time.\r\n\r\nProvide in ISO 8601 format: YYYY-MM-DDThh:mm:ssZ",
            "format": "date-time",
            "nullable": true
          },
          "end_time": {
            "type": "string",
            "description": "Report end time.\r\n\r\nProvide in ISO 8601 format: YYYY-MM-DDThh:mm:ssZ",
            "format": "date-time",
            "nullable": true
          },
          "device_id": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Array of devices by Id to include in report",
            "nullable": true
          },
          "user_id": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Array of users by Id to include in report",
            "nullable": true
          },
          "media_id": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Array of media items by Id to include in report",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents the body of a request to export a report, including details such as the report identifier,  export\r\nformat, activity type, reporting interval, date and time ranges, and filters for devices, users,  and media\r\nitems."
      },
      "ReportParameter": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The parameter identifier used when submitting report requests.\r\nThis is the SSRS parameter name.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The display name/prompt shown to users when entering the parameter value.",
            "nullable": true
          },
          "required": {
            "type": "boolean",
            "description": "Indicates whether this parameter must be provided to generate the report.\r\nTrue if the parameter is not nullable and does not allow blank values."
          },
          "multi_value": {
            "type": "boolean",
            "description": "Indicates whether this parameter accepts multiple values.\r\nWhen true, an array of values can be submitted for this parameter."
          }
        },
        "additionalProperties": false,
        "description": "Represents a parameter definition for a report.\r\nParameters allow filtering and customizing report output (e.g., date range, device selection)."
      },
      "RollbackRequest": {
        "required": [
          "version"
        ],
        "type": "object",
        "properties": {
          "version": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "RollbackResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "newVersion": {
            "type": "integer",
            "format": "int32"
          },
          "restoredRow": {
            "$ref": "#/components/schemas/DataTableRowModel"
          },
          "error": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "RowListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataTableRowModel"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "continuationToken": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "RowVersionModel": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "rowId": {
            "type": "string",
            "nullable": true
          },
          "version": {
            "type": "integer",
            "format": "int32"
          },
          "action": {
            "type": "string",
            "nullable": true
          },
          "data": {
            "type": "object",
            "additionalProperties": { },
            "description": "Free-form JSON object keyed by column `key`; each value is a raw JSON scalar, object, or `media` object.",
            "nullable": true
          },
          "changedFields": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "previousValues": {
            "type": "object",
            "additionalProperties": { },
            "description": "Free-form JSON object keyed by column `key`; each value is a raw JSON scalar, object, or `media` object.",
            "nullable": true
          },
          "changedBy": {
            "type": "string",
            "nullable": true
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "Schedule": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The name of the schedule",
            "nullable": true
          },
          "group_id": {
            "type": "string",
            "description": "The group id to which the schedule belongs",
            "nullable": true
          },
          "tags": {
            "type": "string",
            "description": "The tags associated with the schedule",
            "nullable": true
          },
          "monday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Monday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "tuesday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Tuesday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "wednesday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Wednesday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "thursday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Thursday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "friday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Friday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "saturday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Saturday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "sunday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Sunday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "start_date": {
            "type": "string",
            "description": "The start date for the schedule.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "end_date": {
            "type": "string",
            "description": "The end date for the schedule.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "start_time": {
            "type": "string",
            "description": "The start time for the schedule.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "end_time": {
            "type": "string",
            "description": "The end time for the schedule.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "template_id": {
            "type": "string",
            "description": "The template id for the schedule.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "playlist_id": {
            "type": "string",
            "description": "The playlist id for the schedule.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/ScheduleType"
          },
          "devices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScheduleDevice"
            },
            "description": "The devices associated with the schedule.",
            "nullable": true
          },
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Condition"
            },
            "description": "The conditions associated with the schedule.\r\nOnly applicable for Campaign schedules.",
            "nullable": true
          },
          "priority": {
            "$ref": "#/components/schemas/SchedulePriorityType"
          },
          "id": {
            "type": "string",
            "description": "The schedule id",
            "nullable": true
          },
          "group_name": {
            "type": "string",
            "description": "The name of the group to which the schedule belongs",
            "nullable": true
          },
          "created_on": {
            "type": "string",
            "description": "The date the schedule was created",
            "format": "date-time",
            "nullable": true
          },
          "created_by_id": {
            "type": "string",
            "description": "The user id that created the schedule",
            "nullable": true
          },
          "modified_on": {
            "type": "string",
            "description": "The date the schedule was last modified",
            "format": "date-time",
            "nullable": true
          },
          "modified_by_id": {
            "type": "string",
            "description": "The user id that last modified the schedule",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ScheduleDevice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The device id",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "SchedulePriorityType": {
        "enum": [
          "Normal",
          "High",
          "Highest",
          "Lowest",
          "Low"
        ],
        "type": "string"
      },
      "ScheduleRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The name of the schedule",
            "nullable": true
          },
          "group_id": {
            "type": "string",
            "description": "The group id to which the schedule belongs",
            "nullable": true
          },
          "tags": {
            "type": "string",
            "description": "The tags associated with the schedule",
            "nullable": true
          },
          "monday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Monday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "tuesday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Tuesday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "wednesday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Wednesday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "thursday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Thursday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "friday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Friday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "saturday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Saturday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "sunday": {
            "type": "boolean",
            "description": "Enabled this schedule for playback on Sunday.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "start_date": {
            "type": "string",
            "description": "The start date for the schedule.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "end_date": {
            "type": "string",
            "description": "The end date for the schedule.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "start_time": {
            "type": "string",
            "description": "The start time for the schedule.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "end_time": {
            "type": "string",
            "description": "The end time for the schedule.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "template_id": {
            "type": "string",
            "description": "The template id for the schedule.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "playlist_id": {
            "type": "string",
            "description": "The playlist id for the schedule.\r\nOnly applicable for Playlist and Template schedules.",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/ScheduleType"
          },
          "devices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScheduleDevice"
            },
            "description": "The devices associated with the schedule.",
            "nullable": true
          },
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Condition"
            },
            "description": "The conditions associated with the schedule.\r\nOnly applicable for Campaign schedules.",
            "nullable": true
          },
          "priority": {
            "$ref": "#/components/schemas/SchedulePriorityType"
          }
        },
        "additionalProperties": false,
        "description": "Request model for creating and updating schedules in the RevelDigital platform.\r\nSchedules define when and what content plays on devices by linking templates/playlists to time-based rules."
      },
      "ScheduleRequestJsonPatchDocument": {
        "type": "object",
        "properties": {
          "operations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScheduleRequestOperation"
            },
            "nullable": true,
            "readOnly": true
          },
          "contractResolver": {
            "$ref": "#/components/schemas/IContractResolver"
          }
        },
        "additionalProperties": false
      },
      "ScheduleRequestOperation": {
        "type": "object",
        "properties": {
          "operationType": {
            "$ref": "#/components/schemas/OperationType"
          },
          "path": {
            "type": "string",
            "nullable": true
          },
          "op": {
            "type": "string",
            "nullable": true
          },
          "from": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ScheduleType": {
        "enum": [
          "Playlist",
          "Template",
          "Campaign"
        ],
        "type": "string",
        "description": "The following schedule types are available:\r\n\r\n- Playlist\r\n  Playlist is considered a basic schedule consisting of a single playlist with a date range, time range, and days of the week.\r\n  Schedule properties to consider when using this type include the following: start_date, end_date, start_time, end_time, playlist_id, and monday-sunday\r\n  \r\n- Template\r\n  Template is considered a basic schedule consisting of a single template with a date range, time range, and days of the week.\r\n  Schedule properties to consider when using this type include the following: start_date, end_date, start_time, end_time, template_id, and monday-sunday\r\n  \r\n- Campaign\r\n  Campaign schedules, or 'Smart Schedules', are more advanced consisting of multiple conditions logically grouped to\r\n  determine what, when, and where content is played.\r\n  Schedule properties to consider when using this type include an array of conditions."
      },
      "Source": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The source id",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The source name",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/SourceType"
          },
          "sequence": {
            "type": "integer",
            "description": "The sequence. Lower numbers are displayed first.",
            "format": "int32",
            "nullable": true
          },
          "media_id": {
            "type": "string",
            "description": "The media file id",
            "nullable": true
          },
          "template_id": {
            "type": "string",
            "description": "The template id",
            "nullable": true
          },
          "playlist_id": {
            "type": "string",
            "description": "The playlist id",
            "nullable": true
          },
          "value": {
            "type": "string",
            "description": "The value",
            "nullable": true
          },
          "interval": {
            "type": "integer",
            "description": "The duration in seconds",
            "format": "int32",
            "nullable": true
          },
          "media": {
            "$ref": "#/components/schemas/Media"
          },
          "loop_policy_type": {
            "$ref": "#/components/schemas/LoopPolicyType"
          },
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Condition"
            },
            "description": "The conditions for this source",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a content item within a playlist. A source defines what content to display\r\nand for how long. Sources can reference media files, templates, embedded playlists, URLs, or other content types."
      },
      "SourceType": {
        "enum": [
          "Audio",
          "Command",
          "Flash",
          "Gadget",
          "Image",
          "Pdf",
          "PlaceExchange",
          "Playlist",
          "PowerPoint",
          "Rss",
          "Svg",
          "Template",
          "Text",
          "Twitter",
          "Url",
          "Video",
          "VistarMedia",
          "WebPage",
          "YouTube",
          "VistarMediaEx",
          "DataTable",
          "AdBreak"
        ],
        "type": "string",
        "description": "Specifies the content type of a RevelDigital.Core.PublicApi.Models.Source item within a playlist.\r\nEach source type determines how the content is rendered and what properties are relevant."
      },
      "Template": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Template id",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Template name",
            "nullable": true
          },
          "group_name": {
            "type": "string",
            "description": "Group name",
            "nullable": true
          },
          "group_id": {
            "type": "string",
            "description": "Group id",
            "nullable": true
          },
          "tags": {
            "type": "string",
            "description": "Tags",
            "nullable": true
          },
          "created_on": {
            "type": "string",
            "description": "Created on date",
            "format": "date-time",
            "nullable": true
          },
          "created_by_id": {
            "type": "string",
            "description": "Created by user id",
            "nullable": true
          },
          "modified_on": {
            "type": "string",
            "description": "Modified on date",
            "format": "date-time",
            "nullable": true
          },
          "modified_by_id": {
            "type": "string",
            "description": "Modified by user id",
            "nullable": true
          },
          "script": {
            "type": "string",
            "description": "Template script",
            "nullable": true
          },
          "back_color": {
            "type": "string",
            "description": "Template background color",
            "nullable": true
          },
          "width": {
            "type": "integer",
            "description": "Width",
            "format": "int32",
            "nullable": true
          },
          "height": {
            "type": "integer",
            "description": "Height",
            "format": "int32",
            "nullable": true
          },
          "orientation": {
            "type": "integer",
            "description": "Display orientation in degrees of rotation: 0=Landscape, 90=Portrait, 180=Landscape Reversed, 270=Portrait Reversed",
            "format": "int32",
            "nullable": true
          },
          "modules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Module"
            },
            "description": "Collection of modules/zones that define content areas within this template.\r\nEach module/zone represents a rectangular region where content from a playlist is displayed.\r\nThe terms \"module\" and \"zone\" are used interchangeably.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a screen layout template that defines the visual arrangement of content zones.\r\nTemplates specify where playlists are displayed on screen and are assigned to devices via schedules."
      },
      "TemplateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Template name",
            "nullable": true
          },
          "group_id": {
            "type": "string",
            "description": "Group id",
            "nullable": true
          },
          "tags": {
            "type": "string",
            "description": "Tags (newline-delimited values stored in Description field)",
            "nullable": true
          },
          "script": {
            "type": "string",
            "description": "Template script",
            "nullable": true
          },
          "back_color": {
            "type": "string",
            "description": "Template background color",
            "nullable": true
          },
          "width": {
            "type": "integer",
            "description": "Width",
            "format": "int32",
            "nullable": true
          },
          "height": {
            "type": "integer",
            "description": "Height",
            "format": "int32",
            "nullable": true
          },
          "orientation": {
            "type": "integer",
            "description": "Orientation in degrees of rotation (0=Landscape, 90=Portrait, 180=Landscape Reversed, 270=Portrait Reversed)",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model for creating or updating a template.\r\nUsed for partial updates via PATCH or full updates via PUT."
      },
      "TemplateRequestJsonPatchDocument": {
        "type": "object",
        "properties": {
          "operations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TemplateRequestOperation"
            },
            "nullable": true,
            "readOnly": true
          },
          "contractResolver": {
            "$ref": "#/components/schemas/IContractResolver"
          }
        },
        "additionalProperties": false
      },
      "TemplateRequestOperation": {
        "type": "object",
        "properties": {
          "operationType": {
            "$ref": "#/components/schemas/OperationType"
          },
          "path": {
            "type": "string",
            "nullable": true
          },
          "op": {
            "type": "string",
            "nullable": true
          },
          "from": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "UpdateDataTableRequest": {
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 100,
            "minLength": 0,
            "type": "string",
            "nullable": true
          },
          "description": {
            "maxLength": 500,
            "minLength": 0,
            "type": "string",
            "nullable": true
          },
          "groupId": {
            "type": "string",
            "nullable": true
          },
          "columns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataTableColumnModel"
            },
            "nullable": true
          },
          "cacheTtlSeconds": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "UpdateRowRequest": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "additionalProperties": { },
            "description": "Free-form JSON object keyed by column `key`; each value is a raw JSON scalar, object, or `media` object."
          }
        },
        "additionalProperties": false
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The user id",
            "nullable": true
          },
          "first_name": {
            "type": "string",
            "description": "The first name",
            "nullable": true
          },
          "last_name": {
            "type": "string",
            "description": "The last name",
            "nullable": true
          },
          "city": {
            "type": "string",
            "description": "The city",
            "nullable": true
          },
          "state": {
            "type": "string",
            "description": "The state",
            "nullable": true
          },
          "postal_code": {
            "type": "string",
            "description": "The postal code",
            "nullable": true
          },
          "country": {
            "type": "string",
            "description": "The country",
            "nullable": true
          },
          "home_phone": {
            "type": "string",
            "description": "The home phone number",
            "nullable": true
          },
          "work_phone": {
            "type": "string",
            "description": "The work phone number",
            "nullable": true
          },
          "mobile_phone": {
            "type": "string",
            "description": "The mobile phone number",
            "nullable": true
          },
          "created_on": {
            "type": "string",
            "description": "The date the user was created",
            "format": "date-time",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "The email address",
            "nullable": true
          },
          "role": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The roles assigned to this user",
            "nullable": true
          },
          "user_name": {
            "type": "string",
            "description": "The username",
            "nullable": true
          },
          "last_activity": {
            "type": "string",
            "description": "The date the user last logged in",
            "format": "date-time",
            "nullable": true
          },
          "email_alerts": {
            "type": "boolean",
            "description": "Whether the user has email alerts enabled",
            "nullable": true
          },
          "sms_alerts": {
            "type": "boolean",
            "description": "Whether the user has SMS alerts enabled",
            "nullable": true
          },
          "is_two_factor": {
            "type": "boolean",
            "description": "Whether the user has two-factor authentication enabled",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "User model"
      },
      "VersionListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RowVersionModel"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32"
          },
          "continuationToken": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      }
    },
    "securitySchemes": {
      "Bearer": {
        "type": "oauth2",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://id.reveldigital.com/connect/authorize",
            "tokenUrl": "https://id.reveldigital.com/connect/token",
            "scopes": {
              "webapi": "Web API"
            }
          }
        }
      },
      "ApiKeyInHeader": {
        "type": "apiKey",
        "description": "Utilize a header based API key associated with your Revel Digital account. X-RevelDigital-ApiKey: XXXXXXXX",
        "name": "X-RevelDigital-ApiKey",
        "in": "header"
      },
      "ApiKeyInQuery": {
        "type": "apiKey",
        "description": "Utilize a query based API key associated with your Revel Digital account. api_key=XXXXXXXXX",
        "name": "api_key",
        "in": "query"
      }
    }
  },
  "security": [
    {
      "Bearer": [
        "webapi"
      ],
      "ApiKeyInHeader": [ ],
      "ApiKeyInQuery": [ ]
    }
  ],
  "tags": [
    {
      "name": "Account"
    },
    {
      "name": "AdHawk"
    },
    {
      "name": "Alerts"
    },
    {
      "name": "DataTables"
    },
    {
      "name": "Devices"
    },
    {
      "name": "Media"
    },
    {
      "name": "Playlists"
    },
    {
      "name": "Report"
    },
    {
      "name": "Schedules"
    },
    {
      "name": "Templates"
    },
    {
      "name": "Users"
    }
  ]
}