---
openapi: 3.0.3
info:
  title: TroupeIT API
  description: "Public API for TroupeIT - Stage Management and Performance Production
    Platform.\n\n## Authentication\n\nThe API uses JWT Bearer tokens for authentication.
    Follow these steps:\n\n### 1. Create an API Key\n\nGenerate an API key from your
    [Account Settings](/settings/edit) page. \nSave the secret securely - it's only
    shown once!\n\n### 2. Exchange API Key for Access Token\n\nExchange your API key
    for a JWT access token:\n\n```bash\ncurl -X POST https://app.troupeit.com/api/v1/auth/token
    \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"api_key\": \"your-64-char-hex-api-key\"}'\n```\n\nResponse:\n```json\n{\n
    \ \"access_token\": \"eyJhbGciOiJIUzI1NiJ9...\",\n  \"token_type\": \"Bearer\",\n
    \ \"expires_in\": 21600\n}\n```\n\n### 3. Use the Access Token\n\nInclude the
    access token in the `Authorization` header for all API requests:\n\n```\nAuthorization:
    Bearer eyJhbGciOiJIUzI1NiJ9...\n```\n\n### 4. Token Refresh\n\nAccess tokens expire
    after 6 hours. When expired, exchange your API key for a new token.\n\n## Rate
    Limiting\n\nAPI requests are rate limited to **100 requests per minute** per user.\n\nThe
    token exchange endpoint has a stricter limit of **10 requests per minute** per
    IP.\n\nRate limit information is included in response headers:\n- `X-RateLimit-Limit`:
    Maximum requests allowed per window\n- `X-RateLimit-Remaining`: Requests remaining
    in current window\n- `X-RateLimit-Reset`: Unix timestamp when the window resets\n\n##
    Pagination\n\nList endpoints return paginated results. Use these query parameters:\n-
    `page`: Page number (default: 1)\n- `per_page`: Items per page (default: 25, max:
    100)\n\nPagination metadata is included in the `meta.pagination` object of responses.\n\n##
    Errors\n\nThe API uses conventional HTTP response codes:\n- `200` - Success\n-
    `401` - Unauthorized (invalid or expired token)\n- `403` - Forbidden (valid token
    but no access to resource)\n- `404` - Not Found\n- `429` - Rate Limit Exceeded\n-
    `500` - Internal Server Error\n"
  version: 1.1.0
  contact:
    name: TroupeIT Support
    url: https://app.troupeit.com/about/support
  license:
    name: Proprietary
    url: https://app.troupeit.com/about/tos
servers:
- url: https://app.troupeit.com/api/v1
  description: Production server
security:
- BearerAuth: []
tags:
- name: Authentication
  description: Token exchange and authentication
- name: Events
  description: Event management endpoints
- name: Shows
  description: Show management endpoints (nested under Events)
- name: Show Items
  description: Show item endpoints (simplified access)
paths:
  "/auth/token":
    post:
      tags:
      - Authentication
      summary: Exchange API key for access token
      description: |
        Exchange a long-lived API key for a short-lived JWT access token.

        The API key is created once in the Settings UI and stored securely by the client.
        Access tokens expire after 6 hours and must be refreshed by calling this endpoint again.

        This endpoint is rate limited to 10 requests per minute per IP address.
      operationId: createToken
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - api_key
              properties:
                api_key:
                  type: string
                  description: Your 64-character hex API key from Settings
                  example: a1b2c3d4e5f6789012345678901234567890123456789012345678901234abcd
                  pattern: "^[a-fA-F0-9]{64}$"
            example:
              api_key: a1b2c3d4e5f6789012345678901234567890123456789012345678901234abcd
      responses:
        '200':
          description: Successfully exchanged API key for access token
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/TokenResponse"
              example:
                access_token: eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNTA3ZjFmNzdiY2Y4NmNkNzk5NDM5MDEwIiwiaWF0IjoxNzA0MDY3MjAwLCJleHAiOjE3MDQwODg0MDAsImp0aSI6ImFiYzEyMy1kZWY0NTYifQ.signature
                token_type: Bearer
                expires_in: 21600
        '401':
          description: Invalid API key
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
              example:
                error:
                  code: invalid_grant
                  message: Invalid API key
                meta:
                  request_id: abc123
                  timestamp: '2025-12-29T21:00:00Z'
        '429':
          "$ref": "#/components/responses/RateLimitExceeded"
  "/events":
    get:
      tags:
      - Events
      summary: List events
      description: |
        Returns a paginated list of events for companies the authenticated user has access to.
        Events are ordered by start date (descending).
      operationId: listEvents
      parameters:
      - "$ref": "#/components/parameters/PageParam"
      - "$ref": "#/components/parameters/PerPageParam"
      responses:
        '200':
          description: Successful response
          headers:
            X-RateLimit-Limit:
              "$ref": "#/components/headers/X-RateLimit-Limit"
            X-RateLimit-Remaining:
              "$ref": "#/components/headers/X-RateLimit-Remaining"
            X-RateLimit-Reset:
              "$ref": "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/Event"
                  meta:
                    "$ref": "#/components/schemas/PaginatedMeta"
              example:
                data:
                - id: 507f1f77bcf86cd799439011
                  title: Annual Showcase 2025
                  start_date: '2025-06-15T18:00:00Z'
                  end_date: '2025-06-15T23:00:00Z'
                  submission_deadline: '2025-05-01T23:59:59Z'
                  time_zone: US/Pacific
                  accepting_submissions: true
                  motd:
                  shows_count: 3
                  company:
                    id: 507f1f77bcf86cd799439010
                    name: Example Productions
                  created_at: '2025-01-15T10:30:00Z'
                  updated_at: '2025-03-20T14:45:00Z'
                meta:
                  request_id: abc123-def456
                  timestamp: '2025-12-29T21:00:00Z'
                  pagination:
                    current_page: 1
                    per_page: 25
                    total_pages: 1
                    total_count: 1
                    next_page:
                    prev_page:
        '401':
          "$ref": "#/components/responses/Unauthorized"
        '429':
          "$ref": "#/components/responses/RateLimitExceeded"
  "/events/{eventId}":
    get:
      tags:
      - Events
      summary: Get event details
      description: 'Returns detailed information about a specific event, including
        all its shows.

        '
      operationId: getEvent
      parameters:
      - name: eventId
        in: path
        required: true
        description: The event ID
        schema:
          type: string
          example: 507f1f77bcf86cd799439011
      responses:
        '200':
          description: Successful response
          headers:
            X-RateLimit-Limit:
              "$ref": "#/components/headers/X-RateLimit-Limit"
            X-RateLimit-Remaining:
              "$ref": "#/components/headers/X-RateLimit-Remaining"
            X-RateLimit-Reset:
              "$ref": "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    "$ref": "#/components/schemas/EventDetailed"
                  meta:
                    "$ref": "#/components/schemas/Meta"
        '401':
          "$ref": "#/components/responses/Unauthorized"
        '403':
          "$ref": "#/components/responses/Forbidden"
        '404':
          "$ref": "#/components/responses/NotFound"
        '429':
          "$ref": "#/components/responses/RateLimitExceeded"
  "/events/{eventId}/shows":
    get:
      tags:
      - Shows
      summary: List shows for an event
      description: |
        Returns a paginated list of shows for a specific event.
        Shows are ordered by door time (ascending).
      operationId: listEventShows
      parameters:
      - name: eventId
        in: path
        required: true
        description: The event ID
        schema:
          type: string
          example: 507f1f77bcf86cd799439011
      - "$ref": "#/components/parameters/PageParam"
      - "$ref": "#/components/parameters/PerPageParam"
      responses:
        '200':
          description: Successful response
          headers:
            X-RateLimit-Limit:
              "$ref": "#/components/headers/X-RateLimit-Limit"
            X-RateLimit-Remaining:
              "$ref": "#/components/headers/X-RateLimit-Remaining"
            X-RateLimit-Reset:
              "$ref": "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      "$ref": "#/components/schemas/Show"
                  meta:
                    "$ref": "#/components/schemas/PaginatedMeta"
        '401':
          "$ref": "#/components/responses/Unauthorized"
        '403':
          "$ref": "#/components/responses/Forbidden"
        '404':
          "$ref": "#/components/responses/NotFound"
        '429':
          "$ref": "#/components/responses/RateLimitExceeded"
  "/events/{eventId}/shows/{showId}":
    get:
      tags:
      - Shows
      summary: Get show details
      description: 'Returns detailed information about a specific show, including
        all its items (acts, notes, etc.).

        '
      operationId: getEventShow
      parameters:
      - name: eventId
        in: path
        required: true
        description: The event ID
        schema:
          type: string
          example: 507f1f77bcf86cd799439011
      - name: showId
        in: path
        required: true
        description: The show ID
        schema:
          type: string
          example: 507f1f77bcf86cd799439012
      responses:
        '200':
          description: Successful response
          headers:
            X-RateLimit-Limit:
              "$ref": "#/components/headers/X-RateLimit-Limit"
            X-RateLimit-Remaining:
              "$ref": "#/components/headers/X-RateLimit-Remaining"
            X-RateLimit-Reset:
              "$ref": "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    "$ref": "#/components/schemas/ShowDetailed"
                  meta:
                    "$ref": "#/components/schemas/Meta"
        '401':
          "$ref": "#/components/responses/Unauthorized"
        '403':
          "$ref": "#/components/responses/Forbidden"
        '404':
          "$ref": "#/components/responses/NotFound"
        '429':
          "$ref": "#/components/responses/RateLimitExceeded"
  "/events/{eventId}/shows/{showId}/current_cue":
    get:
      tags:
      - Shows
      summary: Get current running cue
      description: "Returns the currently highlighted/running cue for a show. This
        endpoint is useful for \nintegrations that need to track show progress in
        real-time.\n\nThe response includes:\n- The current cue with full details\n-
        The previous and next cues (for context)\n- Progress information (position
        in show, items remaining)\n- Calculated start time based on door time + preceding
        durations\n\nReturns `null` for `current_cue` if no cue is currently highlighted.\n"
      operationId: getCurrentCue
      parameters:
      - name: eventId
        in: path
        required: true
        description: The event ID
        schema:
          type: string
          example: 507f1f77bcf86cd799439011
      - name: showId
        in: path
        required: true
        description: The show ID
        schema:
          type: string
          example: 507f1f77bcf86cd799439012
      responses:
        '200':
          description: Successful response
          headers:
            X-RateLimit-Limit:
              "$ref": "#/components/headers/X-RateLimit-Limit"
            X-RateLimit-Remaining:
              "$ref": "#/components/headers/X-RateLimit-Remaining"
            X-RateLimit-Reset:
              "$ref": "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    "$ref": "#/components/schemas/CurrentCueResponse"
                  meta:
                    "$ref": "#/components/schemas/Meta"
              example:
                data:
                  show:
                    id: 507f1f77bcf86cd799439012
                    title: Opening Night
                    venue: The Grand Theater
                    room: Main Stage
                    door_time: '2025-06-15T18:00:00Z'
                    show_time: '2025-06-15T19:00:00Z'
                    emergency_message:
                  current_cue:
                    id: 507f1f77bcf86cd799439020
                    sequence: 5
                    type: act
                    duration_seconds: 300
                    note:
                    act:
                      id: 507f1f77bcf86cd799439014
                      stage_name: The Amazing Act
                      short_description: A spectacular aerial performance
                      performer:
                        id: 507f1f77bcf86cd799439015
                        name: Jane Doe
                        username: janedoe
                    calculated_start_time: '2025-06-15T18:15:00Z'
                    is_highlighted: true
                  highlighted_at: '2025-06-15T18:16:30Z'
                  previous_cue:
                    id: 507f1f77bcf86cd799439019
                    sequence: 4
                    type: act
                    title: Opening Act
                    duration_seconds: 180
                  next_cue:
                    id: 507f1f77bcf86cd799439021
                    sequence: 6
                    type: note
                    title: Intermission
                    duration_seconds: 600
                  progress:
                    current_sequence: 5
                    total_items: 12
                    items_remaining: 7
                meta:
                  request_id: abc123-def456
                  timestamp: '2025-06-15T18:17:00Z'
        '401':
          "$ref": "#/components/responses/Unauthorized"
        '403':
          "$ref": "#/components/responses/Forbidden"
        '404':
          "$ref": "#/components/responses/NotFound"
        '429':
          "$ref": "#/components/responses/RateLimitExceeded"
    put:
      tags:
      - Shows
      summary: Set current running cue
      description: "Sets the currently highlighted/running cue for a show. This endpoint
        is designed for \nexternal integrations (e.g., QLab, lighting consoles) to
        sync cue position with TroupeIT.\n\nThe cue can be identified by either:\n-
        `show_item_id`: The unique ID of the show item\n- `sequence`: The sequence
        number in the running order\n\nTo clear the current cue (no cue highlighted),
        send `{ \"show_item_id\": null }`.\n\nWhen the cue is updated, all connected
        web clients receive a real-time update via WebSocket.\n"
      operationId: updateCurrentCue
      parameters:
      - name: eventId
        in: path
        required: true
        description: The event ID
        schema:
          type: string
          example: 507f1f77bcf86cd799439011
      - name: showId
        in: path
        required: true
        description: The show ID
        schema:
          type: string
          example: 507f1f77bcf86cd799439012
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Identify the cue by either show_item_id or sequence number
              properties:
                show_item_id:
                  type: string
                  nullable: true
                  description: The show item ID to highlight, or null to clear
                  example: 507f1f77bcf86cd799439020
                sequence:
                  type: integer
                  description: The sequence number of the cue to highlight
                  example: 5
            examples:
              by_id:
                summary: Set cue by show item ID
                value:
                  show_item_id: 507f1f77bcf86cd799439020
              by_sequence:
                summary: Set cue by sequence number
                value:
                  sequence: 5
              clear:
                summary: Clear current cue
                value:
                  show_item_id:
      responses:
        '200':
          description: Cue updated successfully
          headers:
            X-RateLimit-Limit:
              "$ref": "#/components/headers/X-RateLimit-Limit"
            X-RateLimit-Remaining:
              "$ref": "#/components/headers/X-RateLimit-Remaining"
            X-RateLimit-Reset:
              "$ref": "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    "$ref": "#/components/schemas/CurrentCueResponse"
                  meta:
                    "$ref": "#/components/schemas/Meta"
        '400':
          description: Bad request - must provide show_item_id or sequence
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
              example:
                error:
                  code: bad_request
                  message: Request must include either 'show_item_id' or 'sequence'
                meta:
                  request_id: abc123
                  timestamp: '2025-12-29T21:00:00Z'
        '401':
          "$ref": "#/components/responses/Unauthorized"
        '403':
          "$ref": "#/components/responses/Forbidden"
        '404':
          "$ref": "#/components/responses/NotFound"
        '422':
          description: Failed to update cue
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
              example:
                error:
                  code: update_failed
                  message: Failed to update current cue
                meta:
                  request_id: abc123
                  timestamp: '2025-12-29T21:00:00Z'
        '429':
          "$ref": "#/components/responses/RateLimitExceeded"
  "/show_items/{showItemId}/set_current":
    put:
      tags:
      - Show Items
      summary: Set show item as current cue (simplified)
      description: "Sets this show item as the currently highlighted/running cue for
        its show.\n\nThis simplified endpoint only requires the show_item_id - the
        event and show \nare derived automatically. This makes it ideal for QLab integration
        where each\nNetwork Cue contains only the show_item_id.\n\n**QLab OSC Bridge
        Usage:**\n\nThe TroupeIT QLab import script creates Network Cues that send:\n```\n/troupeit/cue
        <show_item_id>\n```\n\nThe qlab_bridge.py script receives these OSC messages
        and calls this endpoint.\n\nWhen the cue is updated, all connected web clients
        receive a real-time update via WebSocket.\n"
      operationId: setShowItemCurrent
      parameters:
      - name: showItemId
        in: path
        required: true
        description: The show item ID to set as current
        schema:
          type: string
          example: 507f1f77bcf86cd799439020
      responses:
        '200':
          description: Cue updated successfully
          headers:
            X-RateLimit-Limit:
              "$ref": "#/components/headers/X-RateLimit-Limit"
            X-RateLimit-Remaining:
              "$ref": "#/components/headers/X-RateLimit-Remaining"
            X-RateLimit-Reset:
              "$ref": "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    "$ref": "#/components/schemas/CurrentCueResponse"
                  meta:
                    "$ref": "#/components/schemas/Meta"
        '401':
          "$ref": "#/components/responses/Unauthorized"
        '403':
          "$ref": "#/components/responses/Forbidden"
        '404':
          "$ref": "#/components/responses/NotFound"
        '422':
          description: Failed to update cue
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
              example:
                error:
                  code: update_failed
                  message: Failed to update current cue
                meta:
                  request_id: abc123
                  timestamp: '2025-12-29T21:00:00Z'
        '429':
          "$ref": "#/components/responses/RateLimitExceeded"
  "/show_items/{showItemId}/clear_current":
    put:
      tags:
      - Show Items
      summary: Clear current cue for a show
      description: |
        Clears the currently highlighted cue for the show that contains this show item.

        The show_item_id is used only to identify which show to clear - any show_item_id
        from that show will work.

        **QLab OSC Bridge Usage:**

        Send from QLab:
        ```
        /troupeit/cue/clear <show_item_id>
        ```

        When the cue is cleared, all connected web clients receive a real-time update via WebSocket.
      operationId: clearShowItemCurrent
      parameters:
      - name: showItemId
        in: path
        required: true
        description: Any show item ID from the show to clear
        schema:
          type: string
          example: 507f1f77bcf86cd799439020
      responses:
        '200':
          description: Cue cleared successfully
          headers:
            X-RateLimit-Limit:
              "$ref": "#/components/headers/X-RateLimit-Limit"
            X-RateLimit-Remaining:
              "$ref": "#/components/headers/X-RateLimit-Remaining"
            X-RateLimit-Reset:
              "$ref": "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    "$ref": "#/components/schemas/CurrentCueResponse"
                  meta:
                    "$ref": "#/components/schemas/Meta"
              example:
                data:
                  show:
                    id: 507f1f77bcf86cd799439012
                    title: Opening Night
                  current_cue:
                  highlighted_at:
                meta:
                  request_id: abc123
                  timestamp: '2025-12-29T21:00:00Z'
        '401':
          "$ref": "#/components/responses/Unauthorized"
        '403':
          "$ref": "#/components/responses/Forbidden"
        '404':
          "$ref": "#/components/responses/NotFound"
        '422':
          description: Failed to clear cue
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Error"
        '429':
          "$ref": "#/components/responses/RateLimitExceeded"
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        JWT access token obtained by exchanging your API key at POST /auth/token.
        Include in the Authorization header: `Bearer <token>`
  parameters:
    PageParam:
      name: page
      in: query
      description: Page number for pagination
      schema:
        type: integer
        minimum: 1
        default: 1
        example: 1
    PerPageParam:
      name: per_page
      in: query
      description: Number of items per page (max 100)
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 25
        example: 25
  headers:
    X-RateLimit-Limit:
      description: Maximum number of requests allowed per minute
      schema:
        type: integer
        example: 100
    X-RateLimit-Remaining:
      description: Number of requests remaining in the current window
      schema:
        type: integer
        example: 95
    X-RateLimit-Reset:
      description: Unix timestamp when the rate limit window resets
      schema:
        type: integer
        example: 1703887200
  schemas:
    TokenResponse:
      type: object
      description: Access token response from token exchange
      properties:
        access_token:
          type: string
          description: JWT access token to use in Authorization header
          example: eyJhbGciOiJIUzI1NiJ9...
        token_type:
          type: string
          description: Token type (always "Bearer")
          example: Bearer
        expires_in:
          type: integer
          description: Token lifetime in seconds (6 hours)
          example: 21600
      required:
      - access_token
      - token_type
      - expires_in
    Event:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the event
          example: 507f1f77bcf86cd799439011
        title:
          type: string
          description: Event title
          example: Annual Showcase 2025
        start_date:
          type: string
          format: date-time
          nullable: true
          description: Event start date/time (ISO 8601)
          example: '2025-06-15T18:00:00Z'
        end_date:
          type: string
          format: date-time
          nullable: true
          description: Event end date/time (ISO 8601)
          example: '2025-06-15T23:00:00Z'
        submission_deadline:
          type: string
          format: date-time
          nullable: true
          description: Deadline for act submissions
          example: '2025-05-01T23:59:59Z'
        time_zone:
          type: string
          description: Event time zone
          example: US/Pacific
        accepting_submissions:
          type: boolean
          description: Whether the event is accepting submissions
          example: true
        motd:
          type: string
          nullable: true
          description: Message of the day displayed on event page
          example:
        shows_count:
          type: integer
          description: Number of shows in this event
          example: 3
        company:
          "$ref": "#/components/schemas/CompanyRef"
        created_at:
          type: string
          format: date-time
          description: When the event was created
          example: '2025-01-15T10:30:00Z'
        updated_at:
          type: string
          format: date-time
          description: When the event was last updated
          example: '2025-03-20T14:45:00Z'
    EventDetailed:
      allOf:
      - "$ref": "#/components/schemas/Event"
      - type: object
        properties:
          shows:
            type: array
            description: All shows in this event
            items:
              "$ref": "#/components/schemas/Show"
    Show:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the show
          example: 507f1f77bcf86cd799439012
        title:
          type: string
          description: Show title
          example: Opening Night
        venue:
          type: string
          description: Venue name
          example: The Grand Theater
        room:
          type: string
          nullable: true
          description: Room or stage within the venue
          example: Main Stage
        door_time:
          type: string
          format: date-time
          description: When doors open (ISO 8601)
          example: '2025-06-15T18:00:00Z'
        show_time:
          type: string
          format: date-time
          description: When the show starts (ISO 8601)
          example: '2025-06-15T19:00:00Z'
        items_count:
          type: integer
          description: Number of items (acts, notes) in this show
          example: 12
        highlighted_item_id:
          type: string
          nullable: true
          description: ID of the currently highlighted/running show item
          example: 507f1f77bcf86cd799439020
        highlighted_at:
          type: string
          format: date-time
          nullable: true
          description: When the current item was highlighted (ISO 8601)
          example: '2025-06-15T18:16:30Z'
        event_id:
          type: string
          description: ID of the parent event
          example: 507f1f77bcf86cd799439011
        created_at:
          type: string
          format: date-time
          description: When the show was created
          example: '2025-01-20T14:00:00Z'
        updated_at:
          type: string
          format: date-time
          description: When the show was last updated
          example: '2025-03-25T09:30:00Z'
    ShowDetailed:
      allOf:
      - "$ref": "#/components/schemas/Show"
      - type: object
        properties:
          current_cue:
            type: object
            nullable: true
            description: Summary of the currently highlighted cue
            properties:
              highlighted_item_id:
                type: string
                nullable: true
                description: ID of the highlighted show item
                example: 507f1f77bcf86cd799439020
              highlighted_at:
                type: string
                format: date-time
                nullable: true
                description: When the cue was highlighted
                example: '2025-06-15T18:16:30Z'
          items:
            type: array
            description: All items in this show, ordered by sequence
            items:
              "$ref": "#/components/schemas/ShowItem"
    CurrentCueResponse:
      type: object
      description: Response for the current cue endpoint
      properties:
        show:
          "$ref": "#/components/schemas/ShowSummary"
        current_cue:
          "$ref": "#/components/schemas/CurrentCue"
        highlighted_at:
          type: string
          format: date-time
          nullable: true
          description: When the current cue was highlighted
          example: '2025-06-15T18:16:30Z'
        previous_cue:
          "$ref": "#/components/schemas/CueBrief"
        next_cue:
          "$ref": "#/components/schemas/CueBrief"
        progress:
          "$ref": "#/components/schemas/ShowProgress"
    ShowSummary:
      type: object
      description: Brief show information for current cue context
      properties:
        id:
          type: string
          description: Show ID
          example: 507f1f77bcf86cd799439012
        title:
          type: string
          description: Show title
          example: Opening Night
        venue:
          type: string
          description: Venue name
          example: The Grand Theater
        room:
          type: string
          nullable: true
          description: Room or stage
          example: Main Stage
        door_time:
          type: string
          format: date-time
          description: Door time
          example: '2025-06-15T18:00:00Z'
        show_time:
          type: string
          format: date-time
          description: Show time
          example: '2025-06-15T19:00:00Z'
        emergency_message:
          type: string
          nullable: true
          description: Emergency message displayed to crew
          example:
    CurrentCue:
      type: object
      nullable: true
      description: The currently running cue with full details
      properties:
        id:
          type: string
          description: Show item ID
          example: 507f1f77bcf86cd799439020
        sequence:
          type: integer
          description: Position in show
          example: 5
        type:
          type: string
          enum:
          - act
          - note
          - unknown
          description: Type of cue
          example: act
        duration_seconds:
          type: integer
          description: Duration in seconds
          example: 300
        note:
          type: string
          nullable: true
          description: Note text (for note-type items)
          example:
        act:
          "$ref": "#/components/schemas/ActRef"
        calculated_start_time:
          type: string
          format: date-time
          nullable: true
          description: Estimated start time based on door time + preceding durations
          example: '2025-06-15T18:15:00Z'
        is_highlighted:
          type: boolean
          description: Whether this cue is currently highlighted
          example: true
    CueBrief:
      type: object
      nullable: true
      description: Brief cue information for previous/next context
      properties:
        id:
          type: string
          description: Show item ID
          example: 507f1f77bcf86cd799439019
        sequence:
          type: integer
          description: Position in show
          example: 4
        type:
          type: string
          enum:
          - act
          - note
          description: Type of cue
          example: act
        title:
          type: string
          description: Cue title (stage name for acts, note text for notes)
          example: Opening Act
        duration_seconds:
          type: integer
          description: Duration in seconds
          example: 180
    ShowProgress:
      type: object
      description: Progress information for the show
      properties:
        current_sequence:
          type: integer
          nullable: true
          description: Sequence number of current cue
          example: 5
        total_items:
          type: integer
          description: Total number of items in the show
          example: 12
        items_remaining:
          type: integer
          description: Number of items after the current cue
          example: 7
    ShowItem:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the show item
          example: 507f1f77bcf86cd799439013
        sequence:
          type: integer
          description: Position in the show running order
          example: 1
        type:
          type: string
          enum:
          - act
          - note
          - unknown
          description: Type of item
          example: act
        duration_seconds:
          type: integer
          description: Duration of the item in seconds
          example: 300
        note:
          type: string
          nullable: true
          description: Note text (for note-type items)
          example:
        act:
          "$ref": "#/components/schemas/ActRef"
    ActRef:
      type: object
      nullable: true
      description: Act reference (null for note-type items)
      properties:
        id:
          type: string
          description: Act ID
          example: 507f1f77bcf86cd799439014
        stage_name:
          type: string
          description: Performer's stage name
          example: The Amazing Act
        title:
          type: string
          nullable: true
          description: Title of this specific act/routine
          example: Fire Dance Spectacular
        short_description:
          type: string
          nullable: true
          description: Brief description of the act
          example: A spectacular aerial performance
        performer:
          "$ref": "#/components/schemas/PerformerRef"
    PerformerRef:
      type: object
      nullable: true
      description: Performer reference
      properties:
        id:
          type: string
          description: User ID
          example: 507f1f77bcf86cd799439015
        name:
          type: string
          description: Performer's display name
          example: Jane Doe
        username:
          type: string
          description: Performer's username
          example: janedoe
    CompanyRef:
      type: object
      nullable: true
      description: Company reference
      properties:
        id:
          type: string
          description: Company ID
          example: 507f1f77bcf86cd799439010
        name:
          type: string
          description: Company name
          example: Example Productions
    Meta:
      type: object
      description: Response metadata
      properties:
        request_id:
          type: string
          description: Unique identifier for this request
          example: abc123-def456-ghi789
        timestamp:
          type: string
          format: date-time
          description: Response timestamp (ISO 8601)
          example: '2025-12-29T21:00:00Z'
    PaginatedMeta:
      allOf:
      - "$ref": "#/components/schemas/Meta"
      - type: object
        properties:
          pagination:
            "$ref": "#/components/schemas/Pagination"
    Pagination:
      type: object
      description: Pagination information
      properties:
        current_page:
          type: integer
          description: Current page number
          example: 1
        per_page:
          type: integer
          description: Items per page
          example: 25
        total_pages:
          type: integer
          description: Total number of pages
          example: 3
        total_count:
          type: integer
          description: Total number of items
          example: 67
        next_page:
          type: integer
          nullable: true
          description: Next page number (null if on last page)
          example: 2
        prev_page:
          type: integer
          nullable: true
          description: Previous page number (null if on first page)
          example:
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: Error code
              example: not_found
            message:
              type: string
              description: Human-readable error message
              example: Event not found
            retry_after:
              type: integer
              description: Seconds until rate limit resets (only for 429 errors)
              example: 45
        meta:
          "$ref": "#/components/schemas/Meta"
  responses:
    Unauthorized:
      description: Authentication required or invalid/expired access token
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/Error"
          example:
            error:
              code: unauthorized
              message: Invalid or missing access token. Include a valid JWT in the
                Authorization header as 'Bearer <token>'.
            meta:
              request_id: abc123
              timestamp: '2025-12-29T21:00:00Z'
    Forbidden:
      description: Valid authentication but no access to resource
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/Error"
          example:
            error:
              code: forbidden
              message: You do not have access to this event
            meta:
              request_id: abc123
              timestamp: '2025-12-29T21:00:00Z'
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/Error"
          example:
            error:
              code: not_found
              message: Event not found
            meta:
              request_id: abc123
              timestamp: '2025-12-29T21:00:00Z'
    RateLimitExceeded:
      description: Rate limit exceeded
      headers:
        X-RateLimit-Limit:
          "$ref": "#/components/headers/X-RateLimit-Limit"
        X-RateLimit-Remaining:
          schema:
            type: integer
            example: 0
        X-RateLimit-Reset:
          "$ref": "#/components/headers/X-RateLimit-Reset"
      content:
        application/json:
          schema:
            "$ref": "#/components/schemas/Error"
          example:
            error:
              code: rate_limit_exceeded
              message: Rate limit exceeded. Please wait before making more requests.
              retry_after: 45
            meta:
              request_id: abc123
              timestamp: '2025-12-29T21:00:00Z'
