> For the complete documentation index, see [llms.txt](https://docs.firework.com/firework-for-developers/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.firework.com/firework-for-developers/api/insights.md).

# Insights

### 1. Overview

The Firework Insights API provides read-only access to video, livestream, and playlist performance data.

Three endpoints are available today:

* **Get Livestream Insights** (`GET /api/v1/insights/live_streams/{live_stream_id}`) — confirms the caller can access a livestream and returns its encoded ID.
* **Get Video Insights** (`GET /api/v1/insights/videos/{video_id}`) — confirms the caller can access a video and returns its encoded ID.
* **Playlist Video Views** (`GET /api/v1/stats/playlists/{playlist_id}/video_views`) — returns the videos in a playlist, in the embed feed's order and pagination, each with active and replay view counts.

**Base URL**: `https://api.firework.com`

### 2. Authentication

The Firework Insights API uses OAuth 2.0 for authentication. Before using this API, you must obtain an access token.

**Authentication Method:**

* **Client Credentials**: OAuth 2.0 Client Credentials flow for server-to-server authentication (machine-to-machine)

> 📖 **Documentation:**
>
> * [Client Credentials OAuth](/firework-for-developers/api/authentication.md) - Server-to-server authentication for OAuth apps

***

### 3. Endpoint Summary

| Endpoint                                                | Scope           | Notes                                                  |
| ------------------------------------------------------- | --------------- | ------------------------------------------------------ |
| `GET /api/v1/insights/live_streams/{live_stream_id}`    | `insights:read` | Confirm access to a livestream; returns its encoded ID |
| `GET /api/v1/insights/videos/{video_id}`                | `insights:read` | Confirm access to a video; returns its encoded ID      |
| `GET /api/v1/stats/playlists/{playlist_id}/video_views` | `insights:read` | Active and replay view counts for a playlist's videos  |

***

### 4. Get Livestream Insights

Confirms that the authenticated caller can access a livestream and returns its encoded identifier.

**Endpoint**: `GET /api/v1/insights/live_streams/{live_stream_id}` **Authentication**: Bearer token required (OAuth 2.0 Client Credentials) **Required Scope**: `insights:read` (for OAuth apps)

> **Note**: The authenticated caller must have access to the business/channel that owns the livestream.

> 📝 **Note**: This endpoint returns only the acknowledgement below and accepts no query parameters.

#### 4.1. Request Headers

| Name            | Description                           | Required |
| --------------- | ------------------------------------- | -------- |
| `Authorization` | Bearer token: `Bearer {ACCESS_TOKEN}` | ✅        |

#### 4.2. Path Parameters

| Parameter        | Type   | Required | Description                                 |
| ---------------- | ------ | -------- | ------------------------------------------- |
| `live_stream_id` | string | ✅        | Encoded unique identifier of the livestream |

#### 4.3. Query Parameters

None. This endpoint takes no query parameters.

#### 4.4. Get Livestream Insights Response

**Success Response**: `200 OK`

| Field            | Type   | Nullable | Description                                   |
| ---------------- | ------ | -------- | --------------------------------------------- |
| `status`         | string | ❌        | Always `"success"` on a 200 response          |
| `live_stream_id` | string | ❌        | Encoded identifier of the resolved livestream |

#### 4.5. Get Livestream Insights Error Responses

| Status Code        | Description                                                         |
| ------------------ | ------------------------------------------------------------------- |
| `401 Unauthorized` | Missing, invalid, or expired OAuth token                            |
| `403 Forbidden`    | Token lacks the `insights:read` scope, or no access to the business |
| `404 Not Found`    | Livestream not found                                                |

**Error Response Format**:

```json
{
  "error": "Error Message"
}
```

#### 4.6. Examples

**Example: Get Livestream Insights**

**CURL Request**

```bash
curl -X GET "https://api.firework.com/api/v1/insights/live_streams/616dOp" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

**Success Response (200 OK)**

```json
{
  "status": "success",
  "live_stream_id": "616dOp"
}
```

***

### 5. Get Video Insights

Confirms that the authenticated caller can access a video and returns its encoded identifier.

**Endpoint**: `GET /api/v1/insights/videos/{video_id}` **Authentication**: Bearer token required (OAuth 2.0 Client Credentials) **Required Scope**: `insights:read` (for OAuth apps)

> **Note**: The authenticated caller must have access to the business/channel that owns the video.

> 📝 **Note**: This endpoint returns only the acknowledgement below and accepts no query parameters.

#### 5.1. Request Headers

| Name            | Description                           | Required |
| --------------- | ------------------------------------- | -------- |
| `Authorization` | Bearer token: `Bearer {ACCESS_TOKEN}` | ✅        |

#### 5.2. Path Parameters

| Parameter  | Type   | Required | Description                            |
| ---------- | ------ | -------- | -------------------------------------- |
| `video_id` | string | ✅        | Encoded unique identifier of the video |

#### 5.3. Query Parameters

None. This endpoint takes no query parameters.

#### 5.4. Get Video Insights Response

**Success Response**: `200 OK`

| Field      | Type   | Nullable | Description                              |
| ---------- | ------ | -------- | ---------------------------------------- |
| `status`   | string | ❌        | Always `"success"` on a 200 response     |
| `video_id` | string | ❌        | Encoded identifier of the resolved video |

#### 5.5. Get Video Insights Error Responses

| Status Code        | Description                                                         |
| ------------------ | ------------------------------------------------------------------- |
| `401 Unauthorized` | Missing, invalid, or expired OAuth token                            |
| `403 Forbidden`    | Token lacks the `insights:read` scope, or no access to the business |
| `404 Not Found`    | Video not found                                                     |

**Error Response Format**:

```json
{
  "error": "Error Message"
}
```

#### 5.6. Examples

**Example: Get Video Insights**

**CURL Request**

```bash
curl -X GET "https://api.firework.com/api/v1/insights/videos/o9lYEq" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

**Success Response (200 OK)**

```json
{
  "status": "success",
  "video_id": "o9lYEq"
}
```

***

### 6. Playlist Video Views

Returns the videos in a playlist in the **same order and pagination as the embed playlist feed**, each annotated with active and replay view counts. Non-livestream items and videos that have no reporting data return zero views and a `null` `live_stream_id`. A client pages this endpoint exactly as it pages the embed feed.

**Endpoint**: `GET /api/v1/stats/playlists/{playlist_id}/video_views` **Authentication**: Bearer token required (OAuth 2.0 Client Credentials) **Required Scope**: `insights:read` (for OAuth apps) **Pagination**: Yes (cursor-based, forward-only)

> **Note**: The authenticated caller must have at least read access to the playlist's business. This endpoint is a **temporary wrapper over reporting data** and is expected to be **deprecated** once view metrics are available directly in the embed API.

#### 6.1. Request Headers

| Name            | Description                           | Required |
| --------------- | ------------------------------------- | -------- |
| `Authorization` | Bearer token: `Bearer {ACCESS_TOKEN}` | ✅        |

#### 6.2. Path Parameters

| Parameter     | Type   | Required | Description                               |
| ------------- | ------ | -------- | ----------------------------------------- |
| `playlist_id` | string | ✅        | Encoded unique identifier of the playlist |

#### 6.3. Query Parameters

| Parameter        | Type    | Required | Default | Description                                                                                                 |
| ---------------- | ------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| `page_size`      | integer | ❌        | `6`     | Number of videos per page (range 1–30; values above the max are clamped)                                    |
| `after`          | string  | ❌        | None    | Opaque cursor for the next page — pass back the `pagination.cursor` / `links.next` from the prior response  |
| `first_video_id` | string  | ❌        | None    | Encoded video ID to surface as the first item, mirroring the embed feed's first-video behavior              |
| `video_filter`   | string  | ❌        | None    | Feed filter passthrough; matches the embed playlist feed's filtering so this endpoint returns the same page |

> **Note**: The feed is **forward-only**. Only the `after` cursor is honored; there is no backward `before` cursor and the response's `links` object contains no `prev`. Supply a bracketed array (e.g. `after[]=...`) and the request is rejected with `400`.

#### 6.4. Playlist Video Views Response

**Success Response**: `200 OK`

| Field         | Type      | Nullable | Description                                        |
| ------------- | --------- | -------- | -------------------------------------------------- |
| `video_views` | object\[] | ❌        | Videos in the embed feed's order, each with counts |
| `links`       | object    | ❌        | Pagination links (`next`)                          |
| `pagination`  | object    | ❌        | Pagination state (`cursor`, `has_more`)            |

**Video Views Item Object**

| Field            | Type    | Nullable | Description                                                                                   |
| ---------------- | ------- | -------- | --------------------------------------------------------------------------------------------- |
| `video_id`       | string  | ❌        | Encoded video identifier                                                                      |
| `live_stream_id` | string  | ✅        | Encoded livestream identifier; `null` for a non-livestream item or one with no reporting data |
| `active_views`   | integer | ❌        | View count during the live broadcast (`0` for non-livestream items or no reporting data)      |
| `replay_views`   | integer | ❌        | View count from replay (`0` when there is no replay or no reporting data)                     |

**Links Object**

| Field  | Type   | Nullable | Description                                             |
| ------ | ------ | -------- | ------------------------------------------------------- |
| `next` | string | ✅        | Relative path to the next page; `null` on the last page |

**Pagination Object**

| Field      | Type    | Nullable | Description                                                        |
| ---------- | ------- | -------- | ------------------------------------------------------------------ |
| `cursor`   | string  | ✅        | Opaque cursor for the next page; `null` when there is no next page |
| `has_more` | boolean | ❌        | `true` when another page is available                              |

> **Note**: A cursor (and `links.next`) is emitted only when the page is full (`page_size` items returned). A short final page therefore returns `cursor: null`, `next: null`, and `has_more: false`.

#### 6.5. Playlist Video Views Error Responses

| Status Code        | Description                                                                      |
| ------------------ | -------------------------------------------------------------------------------- |
| `400 Bad Request`  | Malformed pagination parameter (e.g. a bracketed `after[]=` array, not a string) |
| `401 Unauthorized` | Missing, invalid, or expired OAuth token                                         |
| `403 Forbidden`    | Token lacks the `insights:read` scope, or no access to the playlist's business   |
| `404 Not Found`    | Playlist not found                                                               |

**Error Response Format**:

```json
{
  "error": "Error Message"
}
```

#### 6.6. Examples

**Example 1: First Page**

**CURL Request**

```bash
curl -X GET "https://api.firework.com/api/v1/stats/playlists/3xKp9L/video_views?page_size=2" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

**Success Response (200 OK)**

```json
{
  "video_views": [
    {
      "video_id": "o9lYEq",
      "live_stream_id": "616dOp",
      "active_views": 320,
      "replay_views": 150
    },
    {
      "video_id": "o8V2Rb",
      "live_stream_id": null,
      "active_views": 0,
      "replay_views": 0
    }
  ],
  "links": {
    "next": "/api/v1/stats/playlists/3xKp9L/video_views?after=video-o8V2Rb&page_size=2"
  },
  "pagination": {
    "cursor": "video-o8V2Rb",
    "has_more": true
  }
}
```

**Example 2: Last Page (Short Page)**

```json
{
  "video_views": [
    {
      "video_id": "p4Qm2N",
      "live_stream_id": null,
      "active_views": 0,
      "replay_views": 0
    }
  ],
  "links": {
    "next": null
  },
  "pagination": {
    "cursor": null,
    "has_more": false
  }
}
```

#### 6.7. Error Responses

```json
// 400 Bad Request - Malformed cursor
{
  "error": "Bad request"
}

// 404 Not Found - Playlist not found
{
  "error": "Not found"
}
```

***

### 7. Data Freshness

Reporting-backed metrics (such as the Playlist Video Views counts) are computed by ETL pipelines and are typically available by **next day**.

| Data Type  | Freshness   | Notes                                     |
| ---------- | ----------- | ----------------------------------------- |
| Engagement | Daily (T+1) | Available by next morning after the event |
| Commerce   | Daily (T+1) | Attribution recomputed daily              |

> **Note**: Real-time or intra-day metrics are not supported in this version. Metrics reflect end-of-day aggregations.
