Appearance
SECTION 8 — ANALYTICS: VOD
44. POST /analytics/video/session/start
Called when a user starts playing VOD content.
Request
http
POST /analytics/video/session/start
Content-Type: application/json
Authorization: Bearer <token>Request Body
json
{
"session_id": "sess_vod_abc001",
"user_id": "user_123",
"device_id": "device_abc123",
"platform": "web",
"app_version": "2.4.1",
"content": {
"content_id": "ep_001",
"content_type": "episode",
"title": "E1: Pilot Episode",
"creator_id": "creator_001",
"creator_name": "Chris Spencer",
"show_id": "show_001",
"show_title": "Chris Spencer Presents",
"season": 1,
"episode_number": 1,
"duration_seconds": 1472,
"is_free": true,
"is_premium": false,
"is_ppv": false,
"rating": "TV-14"
},
"playback": {
"start_position_seconds": 0,
"quality": "auto",
"autoplay": false,
"is_resume": false
},
"device": {
"type": "web",
"os": "macOS",
"os_version": "14.0",
"browser": "Chrome",
"browser_version": "119.0",
"screen_resolution": "1920x1080",
"connection_type": "wifi",
"isp": "Comcast"
},
"geo": { "country": "US", "state": "Georgia", "city": "Atlanta", "timezone": "America/New_York" },
"referrer": { "source": "creator_zone", "page": "/creators/chris-spencer", "section": "free_episodes" },
"timestamp": "2024-11-01T18:00:00Z"
}Request Body Parameters (key fields)
| Field | Type | Required | Description |
|---|---|---|---|
| session_id | string | Yes | Unique view session ID |
| user_id | string | No | User ID (null for guests) |
| device_id | string | Yes | Unique device fingerprint |
| platform | string | Yes | web, ios, android, roku, firetv, appletv |
| content.content_id | string | Yes | Content being played |
| content.content_type | string | Yes | episode, premium, ppv |
| content.duration_seconds | int | Yes | Total content duration |
| content.is_free / is_premium / is_ppv | boolean | Yes | Content type flags |
| playback.start_position_seconds | int | Yes | Position playback started |
| playback.quality | string | Yes | Initial quality |
| playback.is_resume | boolean | Yes | Whether this is a resume |
| device.type | string | Yes | Device type |
| device.connection_type | string | Yes | wifi, cellular, ethernet |
| geo.country | string | Yes | Country code |
| timestamp | string | Yes | ISO 8601 UTC |
Response 200 OK
json
{
"status": "success",
"data": {
"session_id": "sess_vod_abc001",
"accepted": true,
"heartbeat_interval_seconds": 30,
"server_timestamp": "2024-11-01T18:00:00Z"
}
}45. POST /analytics/video/session/heartbeat
Called every 30 seconds during playback.
Request Body (key fields)
| Field | Type | Required | Description |
|---|---|---|---|
| session_id | string | Yes | Active session ID |
| content_id | string | Yes | Content being watched |
| playback.position_seconds | int | Yes | Current position |
| playback.percent_watched | float | Yes | Percentage watched |
| playback.is_playing | boolean | Yes | Is video playing |
| playback.is_buffering | boolean | Yes | Is video buffering |
| playback.quality | string | Yes | Current quality |
| playback.playback_rate | float | Yes | Speed e.g. 1.0, 1.5 |
| performance.buffer_health_seconds | float | Yes | Buffer ahead |
| performance.rebuffer_count | int | Yes | Rebuffer events |
| performance.dropped_frames | int | Yes | Dropped frames |
| performance.bitrate_kbps | int | Yes | Current bitrate |
| engagement.is_tab_active | boolean | Yes | Tab active state |
| timestamp | string | Yes | ISO 8601 UTC |
Response 200 OK
json
{
"status": "success",
"data": {
"session_id": "sess_vod_abc001",
"accepted": true,
"next_heartbeat_seconds": 30,
"server_timestamp": "2024-11-01T18:07:30Z"
}
}46. POST /analytics/video/session/end
Called when playback ends or user exits.
Request Body (key fields)
| Field | Type | Required | Description |
|---|---|---|---|
| session_id | string | Yes | Session ID |
| playback.end_position_seconds | int | Yes | Final playback position |
| playback.total_watch_seconds | int | Yes | Total active watch time |
| playback.percent_completed | float | Yes | Percentage completed |
| playback.completed | boolean | Yes | Whether fully watched |
| playback.end_reason | string | Yes | completed, user_exit, error, timeout, inactivity |
| performance.total_rebuffer_count | int | Yes | Total rebuffer events |
| performance.quality_switches | int | Yes | Quality changes count |
| engagement.total_pause_count | int | Yes | Number of pauses |
| engagement.total_seek_count | int | Yes | Number of seeks |
| timestamp | string | Yes | ISO 8601 UTC |
Response 200 OK
json
{
"status": "success",
"data": {
"session_id": "sess_vod_abc001",
"accepted": true,
"watch_summary": {
"total_watch_seconds": 1350,
"percent_completed": 91,
"completed": false,
"end_reason": "user_exit"
},
"server_timestamp": "2024-11-01T18:22:30Z"
}
}47. POST /analytics/video/events
Post single or batch player interaction events.
Request Body
Send session_id, user_id, device_id, content_id, creator_id, and an events array. Each event has event_id, event_type, position_seconds, timestamp, and optional metadata.
Supported VOD Event Types
| Event Type | Description |
|---|---|
| play | Playback started or resumed |
| pause | Playback paused |
| seek | User seeked to position |
| seek_start / seek_end | Seek began/ended |
| buffer_start / buffer_end | Buffering started/ended |
| quality_change | Stream quality changed |
| volume_change | Volume level changed |
| mute / unmute | Audio muted/unmuted |
| fullscreen_enter / fullscreen_exit | Fullscreen |
| playback_rate_change | Speed changed |
| content_start | First frame rendered |
| content_complete | End of content reached |
| subtitle_on / subtitle_off | Subtitles |
| pip_enter / pip_exit | Picture-in-picture |
| share | User shared content |
| clip | User created a clip |
| like | User liked content |
| tip | User tipped creator |
Response 200 OK
json
{
"status": "success",
"data": {
"session_id": "sess_vod_abc001",
"accepted_count": 7,
"rejected_count": 0,
"rejected_events": [],
"server_timestamp": "2024-11-01T18:24:32Z"
}
}48. POST /analytics/video/quality
Report a stream quality change event.
Request Body (key fields)
| Field | Type | Required | Description |
|---|---|---|---|
| quality_change.from_quality | string | Yes | Previous quality |
| quality_change.to_quality | string | Yes | New quality |
| quality_change.from_bitrate_kbps | int | Yes | Previous bitrate |
| quality_change.to_bitrate_kbps | int | Yes | New bitrate |
| quality_change.trigger | string | Yes | user, auto, network, error |
| quality_change.position_seconds | int | Yes | Position at change |
Response 200 OK
json
{
"status": "success",
"data": {
"session_id": "sess_vod_abc001",
"accepted": true,
"server_timestamp": "2024-11-01T18:04:10Z"
}
}49. POST /analytics/video/error
Report a player or stream error.
Request Body (key fields)
| Field | Type | Required | Description |
|---|---|---|---|
| error.error_code | string | Yes | Internal error code |
| error.error_type | string | Yes | network, decode, drm, timeout, auth, cdn, player |
| error.error_message | string | Yes | Human-readable message |
| error.error_severity | string | Yes | info, warning, critical |
| error.is_fatal | boolean | Yes | Whether playback terminated |
| error.recovery_attempted | boolean | Yes | Whether auto-recovery tried |
| error.recovery_success | boolean | Yes | Whether recovery succeeded |
Response 200 OK
json
{
"status": "success",
"data": {
"session_id": "sess_vod_abc001",
"accepted": true,
"error_id": "err_log_xyz001",
"server_timestamp": "2024-11-01T18:12:30Z"
}
}50. POST /analytics/video/ads
Report ad impression, view, skip, or click.
Request Body
Include session_id, user_id, device_id, content_id, creator_id, ad (ad_id, ad_type, ad_title, ad_duration_seconds, ad_position, etc.), event (event_type, position_seconds, watch_duration_seconds, was_skipped, was_clicked), and timestamp.
Supported Ad Event Types
| Event Type | Description |
|---|---|
| ad_impression | Ad was shown |
| ad_start | Ad started playing |
| ad_quartile_25 / 50 / 75 | 25%/50%/75% of ad watched |
| ad_complete | Ad fully watched |
| ad_skip | Ad was skipped |
| ad_click | Ad was clicked |
| ad_error | Ad failed to load |
Response 200 OK
json
{
"status": "success",
"data": {
"session_id": "sess_vod_abc001",
"ad_id": "ad_xyz001",
"accepted": true,
"server_timestamp": "2024-11-01T18:00:15Z"
}
}