# Live Unique Users — Frontend Integration Returns the **distinct logged-in users who watched a video while it was live**, with their name/email when known. **Paginated.** Intended for the **admin** analytics dashboard. --- ## Endpoint ``` GET /admin/v1/video-analytics/live-unique-users/{videoId}?page=1&pageSize=15 ``` - **Method:** `GET` - **Auth:** Admin only — same authorization as the other `/admin/v1/video-analytics/*` endpoints (e.g. `live-viewers`, `totals`, `graph`). Send the same admin credentials/headers you already use for those. A non-admin / unauthenticated call returns **401**. - **Base URL:** same host you already use for the admin API (per environment). ### Path parameters | Name | Type | Description | |------|------|-------------| | `videoId` | string | The video id. | ### Query parameters | Name | Type | Default | Notes | |------|------|---------|-------| | `page` | number | `1` | 1-based page number. Values `<= 0` are treated as `1`. | | `pageSize` | number | `15` | Items per page. **Max `50`** (larger values are clamped to 50; `<= 0` becomes 1). | --- ## Response `200 OK` Standard pagination envelope (`{ items, totalCount }`): ```jsonc { "items": [ { "userId": "14a29c05-1983-4b14-ba98-a88202bd9493", "name": "Riad Asllani", "email": "riad@gjirafa.com", "portaLink": null }, { "userId": "2f59d36d-e479-40bc-bc29-e6e398c40bd3", "name": null, "email": null, "portaLink": "https://porta-gjirafainc-admin.gjirafa.com/users/2f59d36d-e479-40bc-bc29-e6e398c40bd3/user-details" } ], "totalCount": 30 } ``` ### Top-level fields | Field | Type | Notes | |-------|------|-------| | `totalCount` | number | **Total** distinct logged-in users who watched while live (the full count, not just this page). Use it to compute the number of pages: `Math.ceil(totalCount / pageSize)`. | | `items` | array | Users for the **requested page only**. | ### `items[]` fields | Field | Type | Notes | |-------|------|-------| | `userId` | string | The user's id (Porta/account id). Always present. | | `name` | string \| null | Full name. **`null` when the user was not found** in the internal users DB. | | `email` | string \| null | Email. **`null` when not found** internally. | | `portaLink` | string \| null | **Set only when `name`/`email` are `null`.** Link to look the user up manually in the Porta admin portal. | --- ## How the frontend should render a row For each item in `items`: - **If `name` / `email` are present** → show them normally. - **If they're `null` and `portaLink` is set** → the user isn't in our DB. Render the `userId` and make it (or a "View in Porta" button) link to `portaLink` (open in a new tab) so an admin can look up the details manually. ```jsx items.map(u => u.email ? : ) // pages const totalPages = Math.ceil(totalCount / pageSize); ``` --- ## Behavior notes - **Caching:** results are cached server-side for **~2 minutes**, per `(videoId, page, pageSize)`. Numbers refresh at most every couple of minutes (consistent across requests in that window). The metric is cumulative for the broadcast, so `totalCount` only grows. - **Invalid or unknown `videoId`:** returns `200` with `{ "items": [], "totalCount": 0 }` (not a 404). - **Page out of range:** returns `200` with `items: []` and the real `totalCount`. - **Errors:** unexpected failures return `400` with an error body (same shape as other admin analytics endpoints). --- ## Examples ```bash # first page (default page=1, pageSize=15) curl -X GET "{BASE_URL}/admin/v1/video-analytics/live-unique-users/aZjMMPomjV" \ -H "Authorization: " # page 2, 25 per page curl -X GET "{BASE_URL}/admin/v1/video-analytics/live-unique-users/aZjMMPomjV?page=2&pageSize=25" \ -H "Authorization: " ```