{
  "openapi": "3.1.0",
  "info": {
    "title": "PeraSignage Public API",
    "version": "1.2.0",
    "description": "Public API v1 for server-to-server integrations. Use an organization API key from the panel. Never put the key in a URL or client-side code. Screens, groups and all referenced IDs are organization scoped. Limits per server process: 120 requests/minute/key, 300/minute/organization, 600/minute/IP before authentication. Status is last reported connectivity, not playback proof. Existing device tokens and panel cookies are not accepted. Keys grant selected scopes across the entire organization. Screen-group restrictions are not part of v1. Lists are ordered by id and are not snapshots; changes during pagination may appear on subsequent polls. CORS is not enabled for browser integrations. Media and playlist read/write endpoints require PUBLIC_API_WRITE_ENABLED. Existing keys retain their scopes. Writes require Idempotency-Key; completed operations replay, changed input conflicts, uncertain operations must be reconciled. Publication means saved desired manifests, not confirmed device playback. JSON/file/R2 changes are not in one SQL transaction. Run a single Node writer process, matching existing JSON storage. Upload: one JPEG/PNG/WebP/MP4, maximum 50 MiB; MP4 duration is detected on the server with ffprobe; omit durationSeconds. Analysis verifies video metadata, not full decoding or player codec compatibility. 100 items/playlist, 100 explicit targets/publication. Up to 10000 retained operations per key; operation records are not automatically pruned. Priority image broadcasts require PRIORITY_BROADCAST_ENABLED and priority:write, independently of PUBLIC_API_WRITE_ENABLED. Presets are managed in the panel. Every trigger and device claim checks the current license. Images must be ready in a connected player with priority support (Tizen, Android, webOS, Windows or Browser). Commands do not edit playlists or manifests. A displayed alert closes on a local timer and reveals the then-current normal content. Start deadline: 10 seconds; no offline queue. Shown/finished are player reports, not independent physical display proof. Priority durations are 1 to 86400 integer seconds (24 hours), default 5. Legacy players can still display up to 60 seconds; longer triggers require updated players. Priority idempotency lasts at least 24 hours per organization and actor and is retained through the latest possible completion plus 24 hours; reuse the same key for the same physical event. At most 10000 priority events per organization in a rolling 24 hours. One active priority per screen; no stacking or preemption."
  },
  "servers": [
    {
      "url": "https://api.perasignage.com/v1"
    }
  ],
  "security": [
    {
      "apiKeyBearer": []
    }
  ],
  "tags": [
    {
      "name": "Identity"
    },
    {
      "name": "Screens"
    },
    {
      "name": "Screen groups"
    },
    {
      "name": "Media"
    },
    {
      "name": "Playlists"
    },
    {
      "name": "Publications"
    },
    {
      "name": "Priority broadcasts"
    }
  ],
  "paths": {
    "/me": {
      "get": {
        "operationId": "getIntegrationIdentity",
        "summary": "Inspect the current key",
        "tags": [
          "Identity"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdentityResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid filters or pagination.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Required scope missing.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached. Wait Retry-After seconds before retrying.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Feature not enabled, required isolation unavailable, or temporary database failure.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/screens": {
      "get": {
        "operationId": "listScreens",
        "summary": "List screens",
        "tags": [
          "Screens"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScreenPage"
                }
              }
            }
          },
          "400": {
            "description": "Invalid filters or pagination.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Required scope missing.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached. Wait Retry-After seconds before retrying.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Feature not enabled, required isolation unavailable, or temporary database failure.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "description": "Required scope: `screens:read`. Organization is always derived from the API key.",
        "x-required-scopes": [
          "screens:read"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Number of records per page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque nextCursor from the previous response. Keep the same filters. Null means no next page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "groupId",
            "in": "query",
            "description": "Filter by an owned group ID. Unknown/other-tenant group IDs return an empty list.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "online",
                "offline",
                "unknown"
              ]
            }
          }
        ]
      }
    },
    "/screens/{id}": {
      "get": {
        "operationId": "getScreen",
        "summary": "Read one screen",
        "tags": [
          "Screens"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScreenResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid filters or pagination.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Required scope missing.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached. Wait Retry-After seconds before retrying.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Feature not enabled, required isolation unavailable, or temporary database failure.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "description": "Required scope: `screens:read`. Organization is always derived from the API key.",
        "x-required-scopes": [
          "screens:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/screen-groups": {
      "get": {
        "operationId": "listScreenGroups",
        "summary": "List screen groups",
        "tags": [
          "Screen groups"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScreenGroupPage"
                }
              }
            }
          },
          "400": {
            "description": "Invalid filters or pagination.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Required scope missing.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached. Wait Retry-After seconds before retrying.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Feature not enabled, required isolation unavailable, or temporary database failure.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "description": "Required scope: `screen-groups:read`. Organization is always derived from the API key.",
        "x-required-scopes": [
          "screen-groups:read"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Number of records per page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque nextCursor from the previous response. Keep the same filters. Null means no next page.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/screen-groups/{id}": {
      "get": {
        "operationId": "getScreenGroup",
        "summary": "Read one screen group",
        "tags": [
          "Screen groups"
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScreenGroupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid filters or pagination.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Required scope missing.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached. Wait Retry-After seconds before retrying.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Feature not enabled, required isolation unavailable, or temporary database failure.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "description": "Required scope: `screen-groups:read`. Organization is always derived from the API key.",
        "x-required-scopes": [
          "screen-groups:read"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/media": {
      "get": {
        "operationId": "listMedia",
        "summary": "listMedia",
        "tags": [
          "Media"
        ],
        "x-required-scope": "media:read",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Number of records per page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque nextCursor from the previous response. Keep the same filters. Null means no next page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid filters or pagination.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Required scope missing.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached. Wait Retry-After seconds before retrying.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Feature not enabled, required isolation unavailable, or temporary database failure.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency conflict, pending/uncertain outcome, busy organization, unsupported playlist, or retained operation limit. Do not automatically retry OUTCOME_UNKNOWN.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "JSON body or file exceeds configured limits.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type or invalid file signature.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "200": {
            "description": "Success.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Idempotency-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present only when replaying a stored result."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MediaPage"
                }
              }
            }
          }
        },
        "description": "Available only when PUBLIC_API_WRITE_ENABLED is true. Requires media:read."
      },
      "post": {
        "operationId": "uploadMedia",
        "summary": "uploadMedia",
        "tags": [
          "Media"
        ],
        "x-required-scope": "media:write",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Unique per API key and logical write. Reuse only with identical method/path/body/file bytes/name/MIME. No automatic expiry; retained until key deletion. Completed responses replay with Idempotency-Replayed: true. Pending/uncertain response requires reconciliation.",
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]{16,128}$"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid filters or pagination.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Required scope missing.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached. Wait Retry-After seconds before retrying.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Feature not enabled, required isolation unavailable, or temporary database failure.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency conflict, pending/uncertain outcome, busy organization, unsupported playlist, or retained operation limit. Do not automatically retry OUTCOME_UNKNOWN.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "JSON body or file exceeds configured limits.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type or invalid file signature.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "201": {
            "description": "Success.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Idempotency-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present only when replaying a stored result."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MediaResponse"
                }
              }
            }
          }
        },
        "description": "Available only when PUBLIC_API_WRITE_ENABLED is true. Requires media:write.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/MediaUpload"
              }
            }
          }
        }
      }
    },
    "/media/{id}": {
      "get": {
        "operationId": "getMedia",
        "summary": "getMedia",
        "tags": [
          "Media"
        ],
        "x-required-scope": "media:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid filters or pagination.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Required scope missing.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached. Wait Retry-After seconds before retrying.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Feature not enabled, required isolation unavailable, or temporary database failure.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency conflict, pending/uncertain outcome, busy organization, unsupported playlist, or retained operation limit. Do not automatically retry OUTCOME_UNKNOWN.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "JSON body or file exceeds configured limits.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type or invalid file signature.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "200": {
            "description": "Success.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Idempotency-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present only when replaying a stored result."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MediaResponse"
                }
              }
            }
          }
        },
        "description": "Available only when PUBLIC_API_WRITE_ENABLED is true. Requires media:read."
      }
    },
    "/playlists": {
      "get": {
        "operationId": "listPlaylists",
        "summary": "listPlaylists",
        "tags": [
          "Playlists"
        ],
        "x-required-scope": "playlists:read",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Number of records per page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque nextCursor from the previous response. Keep the same filters. Null means no next page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid filters or pagination.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Required scope missing.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached. Wait Retry-After seconds before retrying.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Feature not enabled, required isolation unavailable, or temporary database failure.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency conflict, pending/uncertain outcome, busy organization, unsupported playlist, or retained operation limit. Do not automatically retry OUTCOME_UNKNOWN.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "JSON body or file exceeds configured limits.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type or invalid file signature.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "200": {
            "description": "Success.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Idempotency-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present only when replaying a stored result."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlaylistPage"
                }
              }
            }
          }
        },
        "description": "Available only when PUBLIC_API_WRITE_ENABLED is true. Requires playlists:read."
      },
      "post": {
        "operationId": "createPlaylist",
        "summary": "createPlaylist",
        "tags": [
          "Playlists"
        ],
        "x-required-scope": "playlists:write",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Unique per API key and logical write. Reuse only with identical method/path/body/file bytes/name/MIME. No automatic expiry; retained until key deletion. Completed responses replay with Idempotency-Replayed: true. Pending/uncertain response requires reconciliation.",
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]{16,128}$"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid filters or pagination.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Required scope missing.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached. Wait Retry-After seconds before retrying.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Feature not enabled, required isolation unavailable, or temporary database failure.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency conflict, pending/uncertain outcome, busy organization, unsupported playlist, or retained operation limit. Do not automatically retry OUTCOME_UNKNOWN.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "JSON body or file exceeds configured limits.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type or invalid file signature.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "201": {
            "description": "Success.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Idempotency-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present only when replaying a stored result."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlaylistResponse"
                }
              }
            }
          }
        },
        "description": "Available only when PUBLIC_API_WRITE_ENABLED is true. Requires playlists:write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlaylistCreate"
              }
            }
          }
        }
      }
    },
    "/playlists/{id}": {
      "get": {
        "operationId": "getPlaylist",
        "summary": "getPlaylist",
        "tags": [
          "Playlists"
        ],
        "x-required-scope": "playlists:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid filters or pagination.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Required scope missing.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached. Wait Retry-After seconds before retrying.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Feature not enabled, required isolation unavailable, or temporary database failure.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency conflict, pending/uncertain outcome, busy organization, unsupported playlist, or retained operation limit. Do not automatically retry OUTCOME_UNKNOWN.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "JSON body or file exceeds configured limits.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type or invalid file signature.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "200": {
            "description": "Success.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Idempotency-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present only when replaying a stored result."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlaylistResponse"
                }
              }
            }
          }
        },
        "description": "Available only when PUBLIC_API_WRITE_ENABLED is true. Requires playlists:read."
      },
      "put": {
        "operationId": "updatePlaylist",
        "summary": "updatePlaylist",
        "tags": [
          "Playlists"
        ],
        "x-required-scope": "playlists:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Unique per API key and logical write. Reuse only with identical method/path/body/file bytes/name/MIME. No automatic expiry; retained until key deletion. Completed responses replay with Idempotency-Replayed: true. Pending/uncertain response requires reconciliation.",
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]{16,128}$"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid filters or pagination.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Required scope missing.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached. Wait Retry-After seconds before retrying.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Feature not enabled, required isolation unavailable, or temporary database failure.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency conflict, pending/uncertain outcome, busy organization, unsupported playlist, or retained operation limit. Do not automatically retry OUTCOME_UNKNOWN.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "JSON body or file exceeds configured limits.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type or invalid file signature.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "200": {
            "description": "Success.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Idempotency-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present only when replaying a stored result."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlaylistResponse"
                }
              }
            }
          }
        },
        "description": "Available only when PUBLIC_API_WRITE_ENABLED is true. Requires playlists:write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlaylistUpdate"
              }
            }
          }
        }
      }
    },
    "/playlists/{id}/publish": {
      "post": {
        "operationId": "publishPlaylist",
        "summary": "publishPlaylist",
        "tags": [
          "Publications"
        ],
        "x-required-scope": "publications:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Unique per API key and logical write. Reuse only with identical method/path/body/file bytes/name/MIME. No automatic expiry; retained until key deletion. Completed responses replay with Idempotency-Replayed: true. Pending/uncertain response requires reconciliation.",
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]{16,128}$"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid filters or pagination.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Required scope missing.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request limit reached. Wait Retry-After seconds before retrying.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Feature not enabled, required isolation unavailable, or temporary database failure.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency conflict, pending/uncertain outcome, busy organization, unsupported playlist, or retained operation limit. Do not automatically retry OUTCOME_UNKNOWN.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "JSON body or file exceeds configured limits.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type or invalid file signature.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "200": {
            "description": "Success. Publication acknowledges saved manifests, not actual playback.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Idempotency-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                },
                "description": "Present only when replaying a stored result."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicationResponse"
                }
              }
            }
          }
        },
        "description": "Available only when PUBLIC_API_WRITE_ENABLED is true. Requires publications:write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublishInput"
              }
            }
          }
        }
      }
    },
    "/priority-broadcasts": {
      "get": {
        "operationId": "listPriorityBroadcasts",
        "summary": "List configured priority images and player readiness",
        "tags": [
          "Priority broadcasts"
        ],
        "x-required-scope": "priority:write",
        "responses": {
          "400": {
            "description": "Invalid body, duration, targets or missing Idempotency-Key. Query parameters are not supported.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Missing priority:write, or current license is not active for a write.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request rate or 10000 retained events per organization/24h limit exceeded. Retry-After applies to request rate limits.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Priority feature, required migration, license verification or database unavailable.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "PRIORITY_NOT_READY (some target lacks a current ready report), PRIORITY_BUSY (an active command exists), or IDEMPOTENCY_CONFLICT (same key with different preset/targets/duration). On readiness/busy rejection no new event was queued. PRIORITY_DURATION_UNSUPPORTED: at least one selected player cannot display this duration; nothing was sent.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "JSON body or file exceeds configured limits.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type or invalid file signature.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "200": {
            "description": "All presets for this account (maximum 40). Contains only owned screens/media IDs; no media URLs or device credentials. Readiness is a recent player cache report, not a delivery guarantee.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PriorityBroadcastList"
                }
              }
            }
          }
        }
      }
    },
    "/priority-broadcasts/commands/{id}": {
      "get": {
        "operationId": "getPriorityCommand",
        "summary": "Read player delivery reports for one priority command",
        "tags": [
          "Priority broadcasts"
        ],
        "x-required-scope": "priority:write",
        "responses": {
          "400": {
            "description": "Invalid body, duration, targets or missing Idempotency-Key. Query parameters are not supported.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Missing priority:write, or current license is not active for a write.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request rate or 10000 retained events per organization/24h limit exceeded. Retry-After applies to request rate limits.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Priority feature, required migration, license verification or database unavailable.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "PRIORITY_NOT_READY (some target lacks a current ready report), PRIORITY_BUSY (an active command exists), or IDEMPOTENCY_CONFLICT (same key with different preset/targets/duration). On readiness/busy rejection no new event was queued. PRIORITY_DURATION_UNSUPPORTED: at least one selected player cannot display this duration; nothing was sent.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "JSON body or file exceeds configured limits.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type or invalid file signature.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "200": {
            "description": "pending = accepted; claimed = start permission issued; shown/finished = player reported. expired = never started within 10 seconds; unknown = no final report before the observation window. A late report may resolve unknown. Event history and idempotency are retained until at least 24 hours after the latest possible completion (start deadline plus duration plus 5 seconds) and pruned on the next trigger. Active long broadcasts are never pruned at 24 hours from creation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PriorityEventResponse"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/priority-broadcasts/{id}/trigger": {
      "post": {
        "operationId": "triggerPriorityBroadcast",
        "summary": "Display a prepared image temporarily on assigned screens",
        "tags": [
          "Priority broadcasts"
        ],
        "x-required-scope": "priority:write",
        "responses": {
          "400": {
            "description": "Invalid body, duration, targets or missing Idempotency-Key. Query parameters are not supported.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "API key missing, invalid, expired or revoked.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "WWW-Authenticate": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Missing priority:write, or current license is not active for a write.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found in this organization.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Request rate or 10000 retained events per organization/24h limit exceeded. Retry-After applies to request rate limits.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Whole seconds until retry.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "503": {
            "description": "Priority feature, required migration, license verification or database unavailable.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "PRIORITY_NOT_READY (some target lacks a current ready report), PRIORITY_BUSY (an active command exists), or IDEMPOTENCY_CONFLICT (same key with different preset/targets/duration). On readiness/busy rejection no new event was queued. PRIORITY_DURATION_UNSUPPORTED: at least one selected player cannot display this duration; nothing was sent.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "413": {
            "description": "JSON body or file exceeds configured limits.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "415": {
            "description": "Unsupported content type or invalid file signature.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "202": {
            "description": "Command stored and live players notified. This acknowledges acceptance, not actual display. Inspect data.id with the command status endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PriorityTriggerResponse"
                }
              }
            }
          },
          "200": {
            "description": "Same logical event replayed; current delivery state returned without another display command.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PriorityTriggerResponse"
                }
              }
            },
            "headers": {
              "Idempotency-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 16,
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]{16,128}$"
            },
            "description": "Unique for each physical event. Retry the same preset, target list and duration with the same key after uncertain HTTP failures. Deduplicated for at least 24h per API key and account, through the latest possible completion plus 24h; different payload conflicts. Never reuse an old key for a new obstruction. Omitted and explicitly set optional fields are different requests."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PriorityTriggerInput"
              },
              "example": {
                "screenIds": [
                  "robot-screen-id"
                ],
                "durationSeconds": 5
              }
            }
          }
        },
        "description": "Requires a current active license, even for retries with an old API key. JPEG/PNG/WebP up to 8 MiB, at most 8294400 decoded pixels. A live player must report this preset revision loaded before trigger. Up to 100 assigned targets; validation is atomic but actual device rendering is independent per screen. Default duration is the preset value; no indefinite mode. At most three images cached per screen. Use a single Node process in this version. Customer software should debounce obstacle signals: trigger once on transition to blocked; re-arm after the robot is clear."
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKeyBearer": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "PeraSignage opaque API key",
        "description": "Organization API key, not a JWT or device token."
      }
    },
    "schemas": {
      "Screen": {
        "type": "object",
        "required": [
          "id",
          "name",
          "groupId",
          "connectionState",
          "lastSeenAt",
          "model",
          "appVersion"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Canonical deviceId. Treat as an opaque identifier."
          },
          "name": {
            "type": "string"
          },
          "groupId": {
            "type": [
              "string",
              "null"
            ]
          },
          "connectionState": {
            "type": "string",
            "enum": [
              "online",
              "offline",
              "unknown"
            ],
            "description": "Derived from the most recent heartbeat (current online window: 90 seconds). Not proof of playback."
          },
          "lastSeenAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "model": {
            "type": "string"
          },
          "appVersion": {
            "type": "string"
          }
        }
      },
      "ScreenGroup": {
        "type": "object",
        "required": [
          "id",
          "name",
          "screenCount",
          "onlineScreenCount",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "screenCount": {
            "type": "integer",
            "minimum": 0
          },
          "onlineScreenCount": {
            "type": "integer",
            "minimum": 0
          },
          "createdAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updatedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "Identity": {
        "type": "object",
        "required": [
          "organization",
          "scopes",
          "expiresAt"
        ],
        "properties": {
          "organization": {
            "type": "object",
            "required": [
              "id",
              "name"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "screens:read",
                "screen-groups:read",
                "media:read",
                "media:write",
                "playlists:read",
                "playlists:write",
                "publications:write",
                "priority:write"
              ]
            }
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Pagination": {
        "type": "object",
        "required": [
          "limit",
          "nextCursor"
        ],
        "properties": {
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Problem": {
        "type": "object",
        "required": [
          "type",
          "title",
          "status",
          "code",
          "detail",
          "requestId"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "code": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          },
          "requestId": {
            "type": "string"
          }
        }
      },
      "ScreenPage": {
        "type": "object",
        "required": [
          "data",
          "pagination"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Screen"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "ScreenResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Screen"
          }
        }
      },
      "ScreenGroupPage": {
        "type": "object",
        "required": [
          "data",
          "pagination"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScreenGroup"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "ScreenGroupResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/ScreenGroup"
          }
        }
      },
      "IdentityResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Identity"
          }
        }
      },
      "Media": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "type": {
            "enum": [
              "image",
              "video"
            ]
          },
          "mimeType": {
            "type": "string"
          },
          "size": {
            "type": "integer",
            "minimum": 0
          },
          "durationSeconds": {
            "type": "number",
            "minimum": 0
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "type",
          "durationSeconds"
        ]
      },
      "PlaylistItemInput": {
        "type": "object",
        "properties": {
          "mediaId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256
          },
          "durationSeconds": {
            "type": "number",
            "minimum": 1,
            "maximum": 3600,
            "description": "Images only; default 8. Videos use media duration metadata and natural playback completion."
          },
          "fit": {
            "enum": [
              "cover",
              "contain",
              "fill"
            ],
            "default": "cover"
          },
          "muted": {
            "type": "boolean",
            "default": false
          }
        },
        "required": [
          "mediaId"
        ],
        "additionalProperties": false
      },
      "PlaylistItem": {
        "type": "object",
        "properties": {
          "mediaId": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "type": "string"
          },
          "durationSeconds": {
            "type": [
              "number",
              "null"
            ]
          },
          "fit": {
            "type": "string"
          },
          "muted": {
            "type": "boolean"
          },
          "supported": {
            "type": "boolean"
          }
        },
        "required": [
          "mediaId",
          "durationSeconds",
          "fit",
          "muted",
          "supported"
        ]
      },
      "Playlist": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlaylistItem"
            }
          },
          "screenIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastPublishedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "items",
          "screenIds",
          "lastPublishedAt"
        ]
      },
      "PlaylistCreate": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/PlaylistItemInput"
            }
          }
        },
        "required": [
          "title",
          "items"
        ],
        "additionalProperties": false
      },
      "PlaylistUpdate": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/PlaylistItemInput"
            }
          }
        },
        "required": [],
        "additionalProperties": false,
        "minProperties": 1
      },
      "PublishInput": {
        "type": "object",
        "properties": {
          "screenIds": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256
            }
          }
        },
        "required": [
          "screenIds"
        ],
        "additionalProperties": false
      },
      "Publication": {
        "type": "object",
        "properties": {
          "playlistId": {
            "type": "string"
          },
          "publishedAt": {
            "type": "string",
            "format": "date-time"
          },
          "screens": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "manifestVersion": {
                  "type": "integer",
                  "minimum": 1
                }
              },
              "required": [
                "id",
                "manifestVersion"
              ]
            }
          }
        },
        "required": [
          "playlistId",
          "publishedAt",
          "screens"
        ]
      },
      "MediaUpload": {
        "type": "object",
        "properties": {
          "media": {
            "type": "string",
            "format": "binary",
            "description": "JPEG/PNG/WebP/MP4 file, maximum 50 MiB."
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "category": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "durationSeconds": {
            "type": "number",
            "exclusiveMinimum": 0,
            "maximum": 86400,
            "description": "Optional legacy field for MP4; omitted for images. Server detects and stores actual file duration with ffprobe, ignoring this hint."
          }
        },
        "required": [
          "media",
          "name",
          "category"
        ],
        "additionalProperties": false
      },
      "MediaResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Media"
          }
        },
        "required": [
          "data"
        ]
      },
      "MediaPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Media"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        },
        "required": [
          "data",
          "pagination"
        ]
      },
      "PlaylistResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Playlist"
          }
        },
        "required": [
          "data"
        ]
      },
      "PlaylistPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Playlist"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        },
        "required": [
          "data",
          "pagination"
        ]
      },
      "PublicationResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Publication"
          }
        },
        "required": [
          "data"
        ]
      },
      "PriorityScreen": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "ready": {
            "type": "boolean",
            "description": "The current image revision is cached by a connected player and that player supports the preset duration. A shorter API override may still be supported if error is duration_unsupported."
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          },
          "maxDurationSeconds": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1,
            "maximum": 86400,
            "description": "Last connected, image-ready player duration capacity. Legacy priority players report 60. Null means no current ready image session."
          }
        },
        "required": [
          "id",
          "name",
          "ready",
          "error",
          "maxDurationSeconds"
        ]
      },
      "PriorityBroadcast": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "mediaId": {
            "type": "string"
          },
          "durationSeconds": {
            "type": "integer",
            "minimum": 1,
            "maximum": 86400
          },
          "fit": {
            "type": "string",
            "enum": [
              "contain",
              "cover"
            ]
          },
          "revision": {
            "type": "string",
            "format": "uuid"
          },
          "screenIds": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "mediaAvailable": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "screens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PriorityScreen"
            }
          }
        },
        "required": [
          "id",
          "name",
          "mediaId",
          "durationSeconds",
          "fit",
          "revision",
          "screenIds",
          "mediaAvailable",
          "createdAt",
          "updatedAt",
          "screens"
        ]
      },
      "PriorityDelivery": {
        "type": "object",
        "properties": {
          "screenId": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "enum": [
              "pending",
              "claimed",
              "shown",
              "finished",
              "failed",
              "expired",
              "unknown"
            ]
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "shownAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "finishedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "durationSeconds": {
            "type": "integer",
            "minimum": 1,
            "maximum": 86400
          },
          "elapsedMs": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 86460000,
            "description": "Player-reported elapsed time, capped at 24 hours plus 60 seconds for delayed callbacks."
          },
          "error": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "screenId",
          "state",
          "expiresAt",
          "shownAt",
          "finishedAt",
          "durationSeconds",
          "elapsedMs",
          "error"
        ]
      },
      "PriorityEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "broadcastId": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "screens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PriorityDelivery"
            }
          }
        },
        "required": [
          "id",
          "broadcastId",
          "name",
          "createdAt",
          "screens"
        ]
      },
      "PriorityTriggerInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "screenIds": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256
            },
            "description": "Subset of screens assigned to this preset. Omit to select all assigned screens. All must be ready; otherwise nothing is queued."
          },
          "durationSeconds": {
            "type": "integer",
            "minimum": 1,
            "maximum": 86400,
            "description": "Integer seconds, 1 to 86400 (24 hours). Optional override; defaults to the preset duration, usually 5. 10 hours = 36000. Every selected player must advertise support for the requested duration; otherwise 409 PRIORITY_DURATION_UNSUPPORTED and nothing is sent."
          }
        }
      },
      "PriorityBroadcastList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PriorityBroadcast"
            }
          }
        },
        "required": [
          "data"
        ]
      },
      "PriorityEventResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/PriorityEvent"
          }
        },
        "required": [
          "data"
        ]
      },
      "PriorityTriggerResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/PriorityEvent"
          },
          "replayed": {
            "type": "boolean"
          }
        },
        "required": [
          "data",
          "replayed"
        ]
      }
    }
  }
}
