{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Rilla Data Export API contracts",
  "description": "Source-derived response schemas with reviewed runtime nullability and synthetic examples. Request schemas reflect controller validation. Descriptions and SQL semantics require review when the API changes.",
  "x-source": {
    "repository": "rillavoice/customer-api",
    "revision": "853c3cf16ea3453c2fc75f10b4e23b3d026f3ca8",
    "files": {
      "src/features/dataExport/types/UsersExport.ts": "d993497e7e2c3d537117bb6f1380291e7309b7d06130ea129e27218c4423252f",
      "src/features/dataExport/types/TeamsExport.ts": "3acee053316de7e76bca43c15ce2b25a5a3d80b082b65a3d96236d4704ded3b0",
      "src/features/dataExport/types/ConversationsExport.ts": "503a424e2374ba6f6cedc2252a48e03a146c4bfc2a31eff18dd7dff81af79773",
      "src/clients/MagiApiClient/types.ts": "8a6eb78df325edb10a55e0a2d3351d15b0f44bca16d9e5721a988f44b24034a5",
      "src/features/dataExport/controllers/UsersExportController.ts": "fd0ed281099fa3701bd674f59ad943e73284bc9a8803b00a66b5f9fdea4292b5",
      "src/features/dataExport/controllers/TeamsExportController.ts": "12d8926a75489fa314da2df9eb63dc1cac763f10ee6f2b52205af83bd2c393b0",
      "src/features/dataExport/controllers/ConversationsExportController.ts": "56fc1b88a2a0a4013ffbe5ec04eb0433c77178f3530c91d3b58982a53602f032",
      "src/features/dataExport/dataProviders/UsersDataProvider.ts": "d68921b3a844b6e0cfc1be619d14d286017eb6e1a24f6abd75b538d93d16ec65",
      "src/features/dataExport/dataProviders/TeamsDataProvider.ts": "d4cc7c7006ca0d7d6490e8031941afb7e33b75e5f8ebafb499d255bac72fa9fc",
      "src/features/dataExport/dataProviders/ConversationsDataProvider.ts": "f73d83b87bb404c682b801d6288a4a699b511f0a0ffd9b28054e42ae7de0f9c0",
      "src/features/dataExport/services/UsersExportService.ts": "851300c30db5b1085eb337036f8aa88781dd027daa65d94440ccf5913e644687",
      "src/features/dataExport/services/TeamsExportService.ts": "042194bca1a560de3b6834075f73f99d7bb905550325366a3d3c7967f921e5c2",
      "src/features/dataExport/services/FilterService.ts": "b7dcda3a3e1240a58891879cf578d4f5a39edf4eed5f0174694274dcb7aa0a2e",
      "src/features/dataExport/utils/mappers.ts": "7df277fe41b7a559a516fd77ddf9b48b41e6e15ef83cbb93df1c0494f479f896",
      "src/features/dataExport/constants/analytics.ts": "861d4021e6e8732ee76bb08edfe1c62ff1fe4d6cc5e02769ee5f4b6bbb39957f"
    }
  },
  "$defs": {
    "TeamMembership": {
      "title": "TeamMembership",
      "description": "A current team membership.",
      "type": "object",
      "properties": {
        "teamId": {
          "type": "string",
          "description": "Rilla team ID.",
          "examples": [
            "44444444-4444-4444-8444-444444444444"
          ]
        },
        "name": {
          "type": "string",
          "description": "Team name.",
          "examples": [
            "West region"
          ]
        }
      },
      "required": [
        "teamId",
        "name"
      ],
      "additionalProperties": true
    },
    "LiveCoachingMetrics": {
      "title": "LiveCoachingMetrics",
      "description": "Metrics for the user as the host being coached. View/comment counts require an Admin or Team Manager coach. Without qualifying coaching activity the object contains zero counts and lastCoachedAt: null.",
      "type": "object",
      "properties": {
        "sessionsHosted": {
          "type": "number",
          "description": "Rooms created in the window for hosts with qualifying coach views or comments in the window. Not all rooms for all hosts.",
          "examples": [
            2
          ]
        },
        "viewEventsReceived": {
          "type": "number",
          "description": "View events received on hosted sessions.",
          "examples": [
            18
          ]
        },
        "uniqueViewers": {
          "type": "number",
          "description": "Unique viewers across hosted sessions.",
          "examples": [
            5
          ]
        },
        "viewDurationMinutes": {
          "type": "number",
          "description": "Sum of viewer participant durations for qualifying hosts, in minutes. Participants are selected by join time; duration can extend beyond the export end time.",
          "examples": [
            64
          ]
        },
        "commentsReceived": {
          "type": "number",
          "description": "Comments received during live coaching.",
          "examples": [
            7
          ]
        },
        "uniqueCommenters": {
          "type": "number",
          "description": "Unique commenters during live coaching.",
          "examples": [
            3
          ]
        },
        "moneySaved": {
          "type": "number",
          "description": "Sum of positive appointment prices attributed by the live-coaching rule: a qualifying sold outcome and a coach view within 7 calendar days before or after the appointment date. Not a proven causal savings amount; no currency code is returned.",
          "examples": [
            1200
          ]
        },
        "lastCoachedAt": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "Timestamp of the last live coaching session (ISO 8601), or null.",
          "examples": [
            "2026-09-01T10:30:00Z"
          ]
        }
      },
      "required": [
        "sessionsHosted",
        "viewEventsReceived",
        "uniqueViewers",
        "viewDurationMinutes",
        "commentsReceived",
        "uniqueCommenters",
        "moneySaved",
        "lastCoachedAt"
      ],
      "additionalProperties": true
    },
    "UsersExport": {
      "title": "UsersExport",
      "description": "One user and their activity metrics. Returned inside users, not as the top-level response. Hidden users are excluded; removed users can still be returned. Identity, role, teams, first recording and lastActive reflect current/all-time data, not the export window.",
      "type": "object",
      "properties": {
        "userId": {
          "type": "string",
          "description": "Rilla user ID.",
          "examples": [
            "33333333-3333-4333-8333-333333333333"
          ]
        },
        "name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Full name. May be null when a source name component is missing.",
          "examples": [
            "Alex Morgan"
          ]
        },
        "email": {
          "type": "string",
          "description": "Email address.",
          "examples": [
            "alex@example.com"
          ]
        },
        "accountSetUp": {
          "type": "boolean",
          "description": "Whether the user has completed account setup.",
          "examples": [
            true
          ]
        },
        "isRemoved": {
          "type": "boolean",
          "description": "Whether the user has been removed/deactivated.",
          "examples": [
            false
          ]
        },
        "role": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Role display name, not a fixed enum. May be null if there is no matching role.",
          "examples": [
            "Sales Rep"
          ]
        },
        "teams": {
          "anyOf": [
            {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TeamMembership"
              }
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Current team memberships, sorted by team name. Null (not an empty array) when the user has no team membership."
        },
        "timeOfFirstRecording": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "Timestamp of the user's first recording (ISO 8601), or null.",
          "examples": [
            "2023-11-02T16:20:00Z"
          ]
        },
        "lastActive": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "Timestamp of the user's last activity (ISO 8601), or null. For reps this is their most recent recording; for other roles, their most recent product activity. Not bounded by the requested date range.",
          "examples": [
            "2026-09-01T09:45:00Z"
          ]
        },
        "hasVoiceId": {
          "type": "boolean",
          "description": "Whether the user has an enrolled voice ID.",
          "examples": [
            true
          ]
        },
        "analyticsViewed": {
          "type": "number",
          "description": "Number of analytics views.",
          "examples": [
            5
          ]
        },
        "appointmentsRecorded": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "description": "Appointments recorded.",
          "examples": [
            46
          ]
        },
        "averageConversationDuration": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "description": "Mean recording duration in seconds, including recordings without a processed conversation. Null when no duration is available.",
          "examples": [
            3150
          ]
        },
        "averageConversationLength": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "description": "Mean rep talk time plus customer talk time in seconds for processed conversations. Excludes silence; null without measurements.",
          "examples": [
            3260
          ]
        },
        "averageScriptCompliance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "description": "Mean checklist score/denominator over completed checklist evaluations on recordings in the window, rounded to two decimals. Fraction; null without usable results. Multiple evaluations can contribute.",
          "examples": [
            0.81
          ]
        },
        "averageTimePerRidealong": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "description": "Average time per ride-along, in seconds.",
          "examples": [
            1800
          ]
        },
        "clipCommentsGiven": {
          "type": "number",
          "description": "Comments given on clips.",
          "examples": [
            3
          ]
        },
        "clipsCreated": {
          "type": "number",
          "description": "Clips created.",
          "examples": [
            6
          ]
        },
        "clipViewDuration": {
          "type": "number",
          "description": "Total clip view duration, in seconds.",
          "examples": [
            43200
          ]
        },
        "commentsReceived": {
          "type": "number",
          "description": "Comments received.",
          "examples": [
            28
          ]
        },
        "commentsRead": {
          "type": "number",
          "description": "Comments read.",
          "examples": [
            21
          ]
        },
        "commentsGiven": {
          "type": "number",
          "description": "Comments given.",
          "examples": [
            12
          ]
        },
        "conversationsCommentedOn": {
          "type": "number",
          "description": "Conversations the user commented on.",
          "examples": [
            15
          ]
        },
        "conversationsRecorded": {
          "type": "number",
          "description": "Distinct recordings made in the window, including recordings that have not produced a processed conversation.",
          "examples": [
            48
          ]
        },
        "conversationsViewed": {
          "type": "number",
          "description": "Conversations viewed.",
          "examples": [
            70
          ]
        },
        "conversationViewDuration": {
          "type": "number",
          "description": "Total conversation view duration, in seconds.",
          "examples": [
            86400
          ]
        },
        "lastRidealongAt": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "Most recent completed ride-along in the requested window; null if none.",
          "examples": [
            "2026-09-01T13:00:00Z"
          ]
        },
        "longestMonologueAverage": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "description": "Median (not arithmetic mean) of the longest rep monologue per conversation, in seconds. The field name is retained for compatibility.",
          "examples": [
            115
          ]
        },
        "longestCustomerMonologueAverage": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "description": "Median of the longest customer monologue per conversation, in seconds. Null without measurements.",
          "examples": [
            52
          ]
        },
        "patienceAverage": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "description": "Mean stored patience metric for conversations recorded in the window; null if no measurement exists. Do not treat it as a percentage.",
          "examples": [
            0.68
          ]
        },
        "percentageOfRepsWithCommentsGiven": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "description": "Manager/admin comment reach divided by the relevant rep count, rounded to two decimals. Uses the conversation recording window, not comment creation time. Fraction (not multiplied by 100); null without an applicable denominator.",
          "examples": [
            null
          ]
        },
        "recordingCompliance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "description": "Eligible recorded appointments divided by eligible appointments, rounded to two decimals. Fraction, not a percentage: 0.92 means 92%. Null when there is no eligible denominator.",
          "examples": [
            0.9
          ]
        },
        "ridealongsReceived": {
          "type": "number",
          "description": "Ride-alongs received.",
          "examples": [
            2
          ]
        },
        "scorecardsReceived": {
          "type": "number",
          "description": "Scorecards received.",
          "examples": [
            9
          ]
        },
        "scorecardsGiven": {
          "type": "number",
          "description": "Scorecards given.",
          "examples": [
            4
          ]
        },
        "talkRatioAverage": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "description": "Mean rep talk ratio, rounded to two decimals. Fraction: 0.53 means 53%; null without measurements.",
          "examples": [
            0.53
          ]
        },
        "totalAppointments": {
          "type": "number",
          "description": "Eligible appointment-attendee rows with appointment end_time in the window and more than 3 hours ago. Compliance-disabled appointments/outcomes are excluded; calendar-only sources are excluded when a CRM integration exists.",
          "examples": [
            51
          ]
        },
        "totalEndOfRidealongsReached": {
          "type": "number",
          "description": "Ride-alongs completed through to the end.",
          "examples": [
            1
          ]
        },
        "totalRidealongsCompleted": {
          "type": "number",
          "description": "Ride-alongs completed.",
          "examples": [
            3
          ]
        },
        "viewedRecordedRatio": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "description": "Self-viewed recorded conversations divided by distinct recordings made in the window, rounded to two decimals. Both recording and view must fall in the window. Can be null even when recordings exist but none were self-viewed; not conversationsViewed / conversationsRecorded.",
          "examples": [
            0.5
          ]
        },
        "liveCoaching": {
          "$ref": "#/$defs/LiveCoachingMetrics",
          "description": "Live coaching metrics. See LiveCoaching."
        }
      },
      "required": [
        "userId",
        "name",
        "email",
        "accountSetUp",
        "isRemoved",
        "role",
        "teams",
        "timeOfFirstRecording",
        "lastActive",
        "hasVoiceId",
        "analyticsViewed",
        "appointmentsRecorded",
        "averageConversationDuration",
        "averageConversationLength",
        "averageScriptCompliance",
        "averageTimePerRidealong",
        "clipCommentsGiven",
        "clipsCreated",
        "clipViewDuration",
        "commentsReceived",
        "commentsRead",
        "commentsGiven",
        "conversationsCommentedOn",
        "conversationsRecorded",
        "conversationsViewed",
        "conversationViewDuration",
        "lastRidealongAt",
        "longestMonologueAverage",
        "longestCustomerMonologueAverage",
        "patienceAverage",
        "percentageOfRepsWithCommentsGiven",
        "recordingCompliance",
        "ridealongsReceived",
        "scorecardsReceived",
        "scorecardsGiven",
        "talkRatioAverage",
        "totalAppointments",
        "totalEndOfRidealongsReached",
        "totalRidealongsCompleted",
        "viewedRecordedRatio",
        "liveCoaching"
      ],
      "additionalProperties": true
    },
    "TeamsExport": {
      "title": "TeamsExport",
      "description": "One team and its analytics. Membership uses current active, non-hidden users. includeSubteams controls descendant roll-up, not which team rows appear. Users can contribute to multiple teams; do not sum teams as an organization total.",
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "Name of the team.",
          "examples": [
            "West Region"
          ]
        },
        "teamId": {
          "type": "string",
          "description": "Rilla team ID.",
          "examples": [
            "team-42"
          ]
        },
        "externalTeamId": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "ID of the team in the connected CRM. null if not linked.",
          "examples": [
            "ST-WEST"
          ]
        },
        "parentTeamId": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "ID of the parent team. null for top-level teams.",
          "examples": [
            null
          ]
        },
        "parentTeamName": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "Name of the parent team. null for top-level teams.",
          "examples": [
            null
          ]
        },
        "analyticsViewed": {
          "type": "number",
          "description": "Number of analytics views by team members.",
          "examples": [
            12
          ]
        },
        "appointmentsRecorded": {
          "type": "number",
          "description": "Appointments that were recorded.",
          "examples": [
            88
          ]
        },
        "averageConversationDuration": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Mean of each member’s mean recording duration, in seconds. Each member with data has equal weight; null if no member has data.",
          "examples": [
            2980
          ]
        },
        "averageConversationLength": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Mean of each member’s mean rep + customer talk time, in seconds; excludes silence. Null without data.",
          "examples": [
            3120
          ]
        },
        "clipCommentsGiven": {
          "type": "number",
          "description": "Comments given on clips.",
          "examples": [
            7
          ]
        },
        "clipsCreated": {
          "type": "number",
          "description": "Clips created.",
          "examples": [
            14
          ]
        },
        "clipViewDuration": {
          "type": "number",
          "description": "Total clip view duration, in seconds.",
          "examples": [
            86400
          ]
        },
        "commentsGiven": {
          "type": "number",
          "description": "Comments given by team members.",
          "examples": [
            41
          ]
        },
        "commentsRead": {
          "type": "number",
          "description": "Comments read by team members.",
          "examples": [
            33
          ]
        },
        "commentsReceived": {
          "type": "number",
          "description": "Comments received by team members.",
          "examples": [
            52
          ]
        },
        "conversationViewDuration": {
          "type": "number",
          "description": "Total conversation view duration, in seconds.",
          "examples": [
            172800
          ]
        },
        "conversationsCommentedOn": {
          "type": "number",
          "description": "Conversations that received at least one comment.",
          "examples": [
            29
          ]
        },
        "conversationsRecorded": {
          "type": "number",
          "description": "Distinct recordings made in the window, including recordings that have not produced a processed conversation.",
          "examples": [
            95
          ]
        },
        "conversationsViewed": {
          "type": "number",
          "description": "Conversations viewed by team members.",
          "examples": [
            140
          ]
        },
        "longestCustomerMonologueAverage": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Mean of members’ median longest customer monologues, in seconds; null without data.",
          "examples": [
            58
          ]
        },
        "longestMonologueAverage": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Mean of members’ median longest rep monologues, in seconds. Each member with data has equal weight; null without data.",
          "examples": [
            102
          ]
        },
        "patienceAverage": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Mean stored patience metric for conversations recorded in the window; null if no measurement exists. Do not treat it as a percentage.",
          "examples": [
            0.71
          ]
        },
        "recordingCompliance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Eligible recorded appointments divided by eligible appointments, rounded to two decimals. Fraction, not a percentage: 0.92 means 92%. Null when there is no eligible denominator.",
          "examples": [
            0.92
          ]
        },
        "ridealongsReceived": {
          "type": "number",
          "description": "Ride-alongs received.",
          "examples": [
            4
          ]
        },
        "scorecardsGiven": {
          "type": "number",
          "description": "Scorecards given.",
          "examples": [
            18
          ]
        },
        "scorecardsReceived": {
          "type": "number",
          "description": "Scorecards received.",
          "examples": [
            22
          ]
        },
        "talkRatioAverage": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Mean rep talk ratio, rounded to two decimals. Fraction: 0.53 means 53%; null without measurements.",
          "examples": [
            0.52
          ]
        },
        "totalAppointments": {
          "type": "number",
          "description": "Eligible appointment-attendee rows with appointment end_time in the window and more than 3 hours ago. Compliance-disabled appointments/outcomes are excluded; calendar-only sources are excluded when a CRM integration exists.",
          "examples": [
            96
          ]
        },
        "totalUsersWhoRecorded": {
          "type": "number",
          "description": "Number of team members who recorded at least one conversation.",
          "examples": [
            9
          ]
        },
        "totalUsers": {
          "type": "number",
          "description": "Total number of users in the team.",
          "examples": [
            11
          ]
        }
      },
      "required": [
        "name",
        "teamId",
        "externalTeamId",
        "parentTeamId",
        "parentTeamName",
        "analyticsViewed",
        "appointmentsRecorded",
        "averageConversationDuration",
        "averageConversationLength",
        "clipCommentsGiven",
        "clipsCreated",
        "clipViewDuration",
        "commentsGiven",
        "commentsRead",
        "commentsReceived",
        "conversationViewDuration",
        "conversationsCommentedOn",
        "conversationsRecorded",
        "conversationsViewed",
        "longestCustomerMonologueAverage",
        "longestMonologueAverage",
        "patienceAverage",
        "recordingCompliance",
        "ridealongsReceived",
        "scorecardsGiven",
        "scorecardsReceived",
        "talkRatioAverage",
        "totalAppointments",
        "totalUsersWhoRecorded",
        "totalUsers"
      ],
      "additionalProperties": true
    },
    "RecordingUser": {
      "title": "RecordingUser",
      "description": "The rep who owns the recording.",
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "description": "Rilla user ID.",
          "examples": [
            "33333333-3333-4333-8333-333333333333"
          ]
        },
        "name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Full name.",
          "examples": [
            "Alex Morgan"
          ]
        },
        "email": {
          "type": "string",
          "description": "Email address.",
          "examples": [
            "alex@example.com"
          ]
        }
      },
      "required": [
        "id",
        "name",
        "email"
      ],
      "additionalProperties": true
    },
    "Viewer": {
      "title": "Viewer",
      "description": "One viewer of the conversation; totals include all-time views, not just views in the export window.",
      "type": "object",
      "properties": {
        "userId": {
          "type": "string",
          "description": "Rilla user ID of the viewer.",
          "examples": [
            "user-014"
          ]
        },
        "name": {
          "type": "string",
          "description": "Name of the viewer.",
          "examples": [
            "Manager Mike"
          ]
        },
        "viewCount": {
          "type": "number",
          "description": "Number of times this user viewed the conversation.",
          "examples": [
            2
          ]
        },
        "totalViewTimeMs": {
          "type": "number",
          "description": "Total time this user spent viewing, in milliseconds.",
          "examples": [
            540000
          ]
        }
      },
      "required": [
        "userId",
        "name",
        "viewCount",
        "totalViewTimeMs"
      ],
      "additionalProperties": true
    },
    "Tracker": {
      "title": "Tracker",
      "description": "An in-checklist tracker. Prefer the tracker-prefixed fields; unprefixed fields are compatibility aliases with the same values.",
      "type": "object",
      "properties": {
        "trackerId": {
          "type": "string",
          "description": "Unique identifier of the tracker. Stable across conversations, so it can be used to group or join tracker results.",
          "examples": [
            "1042"
          ]
        },
        "name": {
          "type": "string",
          "description": "Alias of trackerName.",
          "examples": [
            "Asked about budget"
          ]
        },
        "trackerName": {
          "type": "string",
          "description": "Name of the tracker.",
          "examples": [
            "Asked about budget"
          ]
        },
        "isHit": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Alias of trackerIsHit.",
          "examples": [
            true
          ]
        },
        "trackerIsHit": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Whether the tracker was hit during the conversation.",
          "examples": [
            true
          ]
        },
        "aiScore": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Alias of trackerAiScore.",
          "examples": [
            0.92
          ]
        },
        "trackerAiScore": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "AI-generated score for the tracker.",
          "examples": [
            0.92
          ]
        }
      },
      "required": [
        "trackerId",
        "name",
        "trackerName",
        "isHit",
        "trackerIsHit",
        "aiScore",
        "trackerAiScore"
      ],
      "additionalProperties": true
    },
    "Checklist": {
      "title": "Checklist",
      "description": "Latest completed evaluation per checklist for this conversation. Includes checklist trackers and compatibility aliases.",
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "Alias of checklistName.",
          "examples": [
            "Discovery"
          ]
        },
        "checklistName": {
          "type": "string",
          "description": "Name of the checklist.",
          "examples": [
            "Discovery"
          ]
        },
        "score": {
          "type": "number",
          "description": "Alias of checklistScore.",
          "examples": [
            1
          ]
        },
        "checklistScore": {
          "type": "number",
          "description": "Number of trackers hit on this checklist.",
          "examples": [
            1
          ]
        },
        "denominator": {
          "type": "number",
          "description": "Alias of checklistDenominator.",
          "examples": [
            1
          ]
        },
        "checklistDenominator": {
          "type": "number",
          "description": "Total number of trackers in the checklist.",
          "examples": [
            1
          ]
        },
        "trackerData": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Tracker"
          },
          "description": "The individual trackers evaluated for this checklist. See Tracker."
        }
      },
      "required": [
        "name",
        "checklistName",
        "score",
        "checklistScore",
        "denominator",
        "checklistDenominator",
        "trackerData"
      ],
      "additionalProperties": true
    },
    "AiTracker": {
      "title": "AiTracker",
      "description": "A tracker evaluated outside a checklist (is_in_checklist = false). This array is not a flattened duplicate of checklists.trackerData.",
      "type": "object",
      "properties": {
        "checklistName": {
          "type": "string",
          "description": "Name of the checklist this tracker belongs to.",
          "examples": [
            "Discovery"
          ]
        },
        "trackerId": {
          "type": "string",
          "description": "Unique identifier of the tracker. Stable across conversations, so it can be used to group or join tracker results.",
          "examples": [
            "1043"
          ]
        },
        "trackerName": {
          "type": "string",
          "description": "Name of the tracker.",
          "examples": [
            "Mentioned financing"
          ]
        },
        "isHit": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Whether the tracker was hit during the conversation.",
          "examples": [
            true
          ]
        },
        "aiScore": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "AI-generated score for the tracker.",
          "examples": [
            0.92
          ]
        }
      },
      "required": [
        "checklistName",
        "trackerId",
        "trackerName",
        "isHit",
        "aiScore"
      ],
      "additionalProperties": true
    },
    "CustomerAddress": {
      "title": "CustomerAddress",
      "description": "Address from the linked CRM location. Individual components can be null.",
      "type": "object",
      "properties": {
        "street": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "Street address.",
          "examples": [
            "123 Example Street"
          ]
        },
        "unit": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "Unit or suite.",
          "examples": [
            null
          ]
        },
        "city": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "City.",
          "examples": [
            "New York"
          ]
        },
        "state": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "State or region.",
          "examples": [
            "NY"
          ]
        },
        "zip": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "Postal code.",
          "examples": [
            "10001"
          ]
        },
        "country": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "Country.",
          "examples": [
            "US"
          ]
        }
      },
      "required": [
        "street",
        "unit",
        "city",
        "state",
        "zip",
        "country"
      ],
      "additionalProperties": true
    },
    "ConversationCustomer": {
      "title": "ConversationCustomer",
      "description": "Customer contact and address from the linked CRM context. Individual values can be null.",
      "type": "object",
      "properties": {
        "name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "Customer name.",
          "examples": [
            "Jordan Lee"
          ]
        },
        "email": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "Customer email.",
          "examples": [
            "jordan@example.com"
          ]
        },
        "phone": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "Customer phone number.",
          "examples": [
            "+1-202-555-0142"
          ]
        },
        "address": {
          "anyOf": [
            {
              "$ref": "#/$defs/CustomerAddress"
            },
            {
              "type": "null"
            }
          ],
          "description": "Structured address, or null when no address fields exist."
        }
      },
      "required": [
        "name",
        "email",
        "phone",
        "address"
      ],
      "additionalProperties": true
    },
    "SurveyConversationResult": {
      "title": "SurveyConversationResult",
      "description": "Survey identity plus its free-form result data. Additional upstream metadata may be present.",
      "type": "object",
      "properties": {
        "surveyId": {
          "type": "string",
          "description": "Survey ID.",
          "examples": [
            "55555555-5555-4555-8555-555555555555"
          ]
        },
        "surveyName": {
          "type": "string",
          "description": "Survey name.",
          "examples": [
            "Discovery quality"
          ]
        },
        "data": {
          "type": "object",
          "additionalProperties": true,
          "description": "Free-form results keyed by the survey definition. This is not a fixed schema.",
          "examples": [
            {
              "next_step_confirmed": true
            }
          ]
        }
      },
      "required": [
        "surveyId",
        "surveyName",
        "data"
      ],
      "additionalProperties": true
    },
    "ConversationsExport": {
      "title": "ConversationsExport",
      "description": "One processed conversation, including linked CRM data, customer, coaching results and temporary download URLs. Also returned directly by GET /export/conversations/{conversationId}.",
      "type": "object",
      "properties": {
        "conversationId": {
          "type": "string",
          "description": "ID of the conversation.",
          "examples": [
            "11111111-1111-4111-8111-111111111111"
          ]
        },
        "recordingId": {
          "type": "string",
          "description": "ID of the underlying recording.",
          "examples": [
            "22222222-2222-4222-8222-222222222222"
          ]
        },
        "date": {
          "type": "string",
          "description": "Recording start timestamp in ISO 8601 UTC. List selection uses inclusive date bounds.",
          "examples": [
            "2026-09-01T14:00:00Z"
          ]
        },
        "processedDate": {
          "type": "string",
          "description": "Date/time the conversation finished processing (ISO 8601).",
          "examples": [
            "2026-09-01T15:12:00Z"
          ]
        },
        "title": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Title of the conversation / appointment.",
          "examples": [
            "Home estimate - Jordan Lee"
          ]
        },
        "duration": {
          "type": "number",
          "description": "Processed conversation duration in seconds.",
          "examples": [
            3240
          ]
        },
        "crmEventID": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "ID of the associated CRM / calendar event.",
          "examples": [
            "evt-90817"
          ]
        },
        "user": {
          "$ref": "#/$defs/RecordingUser",
          "description": "The rep who recorded the conversation: { id, name, email }."
        },
        "transcriptUrl": {
          "type": "string",
          "description": "Temporary presigned S3 URL for the conversation's transcript. Expires 6 hours after the response is issued — download or persist the file rather than storing the URL. Temporary signing credentials may cause earlier expiry.",
          "examples": [
            "https://example.com/temporary-transcript.json?signature=EXAMPLE"
          ]
        },
        "jobNumber": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Job number from the CRM / calendar event.",
          "examples": [
            "JOB-4471"
          ]
        },
        "stLink": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "ServiceTitan job link when the linked appointment uses that integration; null otherwise. Not a generic CRM URL.",
          "examples": [
            "https://go.servicetitan.com/jobs/4471"
          ]
        },
        "totalSold": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Price on the linked appointment in its source currency, or null. This field alone does not establish a sold outcome; no currency code is returned.",
          "examples": [
            12500
          ]
        },
        "outcome": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Outcome of the appointment.",
          "examples": [
            "Sold"
          ]
        },
        "jobSummary": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "AI-generated summary of the job.",
          "examples": [
            "Rep walked the customer through the premium package and scheduled install."
          ]
        },
        "customSummary": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Admin summary / custom insights in your organization's format.",
          "examples": [
            "Customer expressed interest in premium package..."
          ]
        },
        "repSpeedWPM": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Rep speaking speed, in words per minute.",
          "examples": [
            148
          ]
        },
        "repTalkRatio": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Fraction of time the rep was talking (0–1).",
          "examples": [
            0.54
          ]
        },
        "longestRepMonologue": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Longest uninterrupted rep monologue, in seconds.",
          "examples": [
            120
          ]
        },
        "longestCustomerMonologue": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Longest uninterrupted customer monologue, in seconds.",
          "examples": [
            64
          ]
        },
        "totalComments": {
          "type": "number",
          "description": "All-time comments on this conversation, not bounded by the request window.",
          "examples": [
            3
          ]
        },
        "rillaUrl": {
          "type": "string",
          "description": "Link to view the conversation in the Rilla web app.",
          "examples": [
            "https://app.rilla.com/conversations/single?id=11111111-1111-4111-8111-111111111111"
          ]
        },
        "audioUrl": {
          "type": "string",
          "description": "Temporary presigned S3 URL for the conversation's audio recording. Expires 6 hours after the response is issued — download or persist the file rather than storing the URL. Temporary signing credentials may cause earlier expiry.",
          "examples": [
            "https://example.com/temporary-audio.mp3?signature=EXAMPLE"
          ]
        },
        "viewers": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Viewer"
          },
          "description": "Users who viewed the conversation. See Viewer."
        },
        "checklists": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Checklist"
          },
          "description": "Coaching checklists scored for the conversation. Each checklist contains its trackers. See Checklist."
        },
        "aiTrackers": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/AiTracker"
          },
          "description": "Trackers outside the checklist, from the latest completed evaluations. Not a flattened copy of checklists.trackerData."
        },
        "customFields": {
          "anyOf": [
            {
              "type": "object",
              "additionalProperties": true
            },
            {
              "type": "null"
            }
          ],
          "description": "Custom fields from the calendar event. Keys and values are customer-defined. null if none are set.",
          "examples": [
            {
              "leadSource": "Website"
            }
          ]
        },
        "customer": {
          "anyOf": [
            {
              "$ref": "#/$defs/ConversationCustomer"
            },
            {
              "type": "null"
            }
          ],
          "description": "Linked customer contact and structured address; null when no customer fields exist."
        },
        "surveyResults": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/SurveyConversationResult"
          },
          "description": "Survey results. Each result includes a survey ID, name and customer-defined data; the upstream service may include additional metadata."
        }
      },
      "required": [
        "conversationId",
        "recordingId",
        "date",
        "processedDate",
        "title",
        "duration",
        "crmEventID",
        "user",
        "transcriptUrl",
        "jobNumber",
        "stLink",
        "totalSold",
        "outcome",
        "jobSummary",
        "customSummary",
        "repSpeedWPM",
        "repTalkRatio",
        "longestRepMonologue",
        "longestCustomerMonologue",
        "totalComments",
        "rillaUrl",
        "audioUrl",
        "viewers",
        "checklists",
        "aiTrackers",
        "customFields",
        "customer",
        "surveyResults"
      ],
      "additionalProperties": true
    },
    "RecordingsExport": {
      "title": "RecordingsExport",
      "description": "A recording awaiting upload. No conversation, transcript or coaching results exist yet.",
      "type": "object",
      "properties": {
        "recordingId": {
          "type": "string",
          "description": "ID of the recording.",
          "examples": [
            "rec-2b91d3aa"
          ]
        },
        "date": {
          "type": "string",
          "description": "Date/time the recording was made (ISO 8601).",
          "examples": [
            "2026-09-01T17:45:00Z"
          ]
        },
        "title": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Title of the recording / appointment.",
          "examples": [
            "Panel Upgrade - Sarah Lee"
          ]
        },
        "duration": {
          "type": "number",
          "description": "Duration in seconds.",
          "examples": [
            1860
          ]
        },
        "crmEventID": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "ID of the associated CRM / calendar event.",
          "examples": [
            "evt-90932"
          ]
        },
        "user": {
          "$ref": "#/$defs/RecordingUser",
          "description": "The rep who made the recording: { id, name, email }."
        },
        "jobNumber": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Job number from the CRM / calendar event.",
          "examples": [
            "JOB-4519"
          ]
        },
        "stLink": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "ServiceTitan job link when the linked appointment uses that integration; null otherwise. Not a generic CRM URL.",
          "examples": [
            "https://go.servicetitan.com/jobs/4519"
          ]
        },
        "totalSold": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Price on the linked appointment in its source currency, or null. This field alone does not establish a sold outcome; no currency code is returned.",
          "examples": [
            null
          ]
        },
        "outcome": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Outcome of the appointment. null if no outcome is recorded.",
          "examples": [
            null
          ]
        },
        "customFields": {
          "anyOf": [
            {
              "type": "object",
              "additionalProperties": true
            },
            {
              "type": "null"
            }
          ],
          "description": "Custom fields from the calendar event. Keys and values are customer-defined. null if none are set.",
          "examples": [
            {
              "leadSource": "Website"
            }
          ]
        }
      },
      "required": [
        "recordingId",
        "date",
        "title",
        "duration",
        "crmEventID",
        "user",
        "jobNumber",
        "stLink",
        "totalSold",
        "outcome",
        "customFields"
      ],
      "additionalProperties": true
    },
    "ErroredRecordingsExport": {
      "title": "ErroredRecordingsExport",
      "description": "A recording that did not produce a conversation. Includes recording fields plus its processing timestamp and error.",
      "type": "object",
      "properties": {
        "recordingId": {
          "type": "string",
          "description": "ID of the recording.",
          "examples": [
            "rec-2b91d3aa"
          ]
        },
        "date": {
          "type": "string",
          "description": "Date/time the recording was made (ISO 8601).",
          "examples": [
            "2026-09-01T17:45:00Z"
          ]
        },
        "title": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Title of the recording / appointment.",
          "examples": [
            "Panel Upgrade - Sarah Lee"
          ]
        },
        "duration": {
          "type": "number",
          "description": "Duration in seconds.",
          "examples": [
            1860
          ]
        },
        "crmEventID": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "ID of the associated CRM / calendar event.",
          "examples": [
            "evt-90932"
          ]
        },
        "user": {
          "$ref": "#/$defs/RecordingUser",
          "description": "The rep who made the recording: { id, name, email }."
        },
        "jobNumber": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Job number from the CRM / calendar event.",
          "examples": [
            "JOB-4519"
          ]
        },
        "stLink": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "ServiceTitan job link when the linked appointment uses that integration; null otherwise. Not a generic CRM URL.",
          "examples": [
            "https://go.servicetitan.com/jobs/4519"
          ]
        },
        "totalSold": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Price on the linked appointment in its source currency, or null. This field alone does not establish a sold outcome; no currency code is returned.",
          "examples": [
            null
          ]
        },
        "outcome": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "x-runtime-note": "SQL LEFT JOIN or aggregate can return null without a fallback; mapper passes it through.",
          "description": "Outcome of the appointment. null if no outcome is recorded.",
          "examples": [
            null
          ]
        },
        "customFields": {
          "anyOf": [
            {
              "type": "object",
              "additionalProperties": true
            },
            {
              "type": "null"
            }
          ],
          "description": "Custom fields from the calendar event. Keys and values are customer-defined. null if none are set.",
          "examples": [
            {
              "leadSource": "Website"
            }
          ]
        },
        "processedDate": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "description": "Date/time processing finished (ISO 8601).",
          "examples": [
            "2026-09-01T10:02:00Z"
          ]
        },
        "error": {
          "type": "string",
          "description": "Why the recording did not produce a conversation, e.g. AUDIO_TOO_SHORT or NO_TRANSCRIPT.",
          "examples": [
            "AUDIO_TOO_SHORT"
          ]
        }
      },
      "required": [
        "recordingId",
        "date",
        "title",
        "duration",
        "crmEventID",
        "user",
        "jobNumber",
        "stLink",
        "totalSold",
        "outcome",
        "customFields",
        "processedDate",
        "error"
      ],
      "additionalProperties": true
    },
    "UsersExportResponse": {
      "title": "UsersExportResponse",
      "description": "Complete response envelope for POST /export/users. No pagination.",
      "type": "object",
      "properties": {
        "users": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/UsersExport"
          },
          "description": "One UsersExport for each selected user. An empty array means no users matched."
        }
      },
      "required": [
        "users"
      ],
      "additionalProperties": true
    },
    "TeamsExportResponse": {
      "title": "TeamsExportResponse",
      "description": "Complete response envelope for POST /export/teams. No pagination.",
      "type": "object",
      "properties": {
        "teams": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/TeamsExport"
          },
          "description": "One TeamsExport per selected team."
        }
      },
      "required": [
        "teams"
      ],
      "additionalProperties": true
    },
    "ConversationsExportResponse": {
      "title": "ConversationsExportResponse",
      "description": "Paginated response. Each array is independently paginated with the same page and limit.",
      "type": "object",
      "properties": {
        "currentPage": {
          "type": "number",
          "description": "Requested page (1-based).",
          "examples": [
            1
          ]
        },
        "totalPages": {
          "type": "number",
          "description": "Maximum page count across all returned arrays; zero when all are empty.",
          "examples": [
            1
          ]
        },
        "totalConversations": {
          "type": "number",
          "description": "Total matching processed conversations.",
          "examples": [
            1
          ]
        },
        "totalAwaitingUpload": {
          "type": "number",
          "description": "Total matching awaiting-upload recordings. Omitted with processedDate.",
          "examples": [
            1
          ]
        },
        "totalErrored": {
          "type": "number",
          "description": "Total matching errored recordings.",
          "examples": [
            1
          ]
        },
        "conversations": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ConversationsExport"
          },
          "description": "Processed conversations on this page."
        },
        "awaitingUpload": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/RecordingsExport"
          },
          "description": "Recordings still awaiting upload. Omitted with processedDate."
        },
        "errored": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ErroredRecordingsExport"
          },
          "description": "Errored recordings on this page."
        }
      },
      "required": [
        "currentPage",
        "totalPages",
        "totalConversations",
        "totalErrored",
        "conversations",
        "errored"
      ],
      "additionalProperties": true
    }
  },
  "x-requests": {
    "UsersExportRequest": {
      "type": "object",
      "properties": {
        "fromDate": {
          "type": "string",
          "format": "date-time",
          "pattern": "Z$"
        },
        "toDate": {
          "type": "string",
          "format": "date-time",
          "pattern": "Z$"
        },
        "users": {
          "type": "array",
          "items": {
            "type": "string",
            "format": "email"
          }
        }
      },
      "required": [
        "fromDate",
        "toDate"
      ],
      "additionalProperties": true
    },
    "TeamsExportRequest": {
      "type": "object",
      "properties": {
        "fromDate": {
          "type": "string",
          "format": "date-time",
          "pattern": "Z$"
        },
        "toDate": {
          "type": "string",
          "format": "date-time",
          "pattern": "Z$"
        },
        "includeSubteams": {
          "type": "boolean"
        }
      },
      "required": [
        "fromDate",
        "toDate"
      ],
      "additionalProperties": true
    },
    "ConversationsExportRequest": {
      "type": "object",
      "properties": {
        "fromDate": {
          "type": "string",
          "format": "date-time",
          "pattern": "Z$"
        },
        "toDate": {
          "type": "string",
          "format": "date-time",
          "pattern": "Z$"
        },
        "dateType": {
          "type": "string",
          "enum": [
            "timeOfRecording",
            "processedDate"
          ]
        },
        "page": {
          "type": "integer",
          "exclusiveMinimum": 0
        },
        "limit": {
          "type": "integer",
          "exclusiveMinimum": 0,
          "maximum": 50
        },
        "users": {
          "type": "array",
          "items": {
            "type": "string",
            "format": "email"
          }
        }
      },
      "required": [
        "fromDate",
        "toDate"
      ],
      "additionalProperties": true
    }
  }
}
