Skip to content

Telemetry API Endpoints

All Telemetry endpoints live under the same Core API server. Authentication uses the same JWT tokens. The compliance middleware enriches every request with geo, device, and consent context before processing.

Media Events

Track Media Event

http
POST /v1/media/events

Primary endpoint for all video/exercise session tracking. The frontend sends events throughout the playback lifecycle.

Request:

json
{
  "event": "session_start",
  "session_id": "550e8400-e29b-41d4-a716-446655440000",
  "media_id": "exercise-uuid-hashed",
  "media_type": "video",
  "timestamp": "2026-02-17T10:00:00Z",
  "data": {
    "total_duration_seconds": 120.5,
    "connection_type": "wifi",
    "ttfb_ms": 340,
    "video_load_time_ms": 1200,
    "cdn_response_time_ms": 280
  }
}

Supported events: See media-events.md for the full event specification.

Response: 202 Accepted (async processing)

json
{
  "status": "accepted",
  "event_id": "...",
  "session_id": "550e8400-e29b-41d4-a716-446655440000"
}

Consent requirement: Level 2+ (analytics consent — media session data). For error-only troubleshooting at Level 1, use POST /v1/errors/report instead.

Get Bandwidth Statistics

http
GET /v1/media/bandwidth/stats?period=7d&group_by=country_code

Query Parameters:

  • period (string) — Time window: 1h, 24h, 7d, 30d (default: 7d)
  • group_by (string) — Grouping dimension: country_code, device_type, connection_type, browser_family
  • media_id (string) — Filter by specific exercise/video (optional)

Response:

json
{
  "period": "7d",
  "group_by": "country_code",
  "stats": [
    {
      "country_code": "RO",
      "total_sessions": 1250,
      "avg_ttfb_ms": 280,
      "avg_load_time_ms": 950,
      "avg_buffering_count": 0.8,
      "avg_buffering_duration_ms": 400,
      "avg_bitrate": 2800000,
      "completion_rate": 0.82,
      "error_rate": 0.02
    },
    {
      "country_code": "IT",
      "total_sessions": 340,
      "avg_ttfb_ms": 1200,
      "avg_load_time_ms": 3400,
      "avg_buffering_count": 3.2,
      "avg_buffering_duration_ms": 4500,
      "avg_bitrate": 1200000,
      "completion_rate": 0.54,
      "error_rate": 0.12
    }
  ]
}

Get Session Statistics

http
GET /v1/media/sessions/stats?period=7d

Query Parameters:

  • period (string) — Time window: 1h, 24h, 7d, 30d
  • status (string) — Filter by session status: completed, abandoned, active

Response:

json
{
  "period": "7d",
  "total_sessions": 4580,
  "completed": 3280,
  "abandoned": 1100,
  "active": 200,
  "avg_watch_time_seconds": 85.4,
  "avg_completion_percent": 72.3,
  "performance": {
    "p50_ttfb_ms": 300,
    "p95_ttfb_ms": 1800,
    "p50_load_time_ms": 900,
    "p95_load_time_ms": 4500,
    "p50_buffer_duration_ms": 200,
    "p95_buffer_duration_ms": 5000
  }
}

Analytics

Track Analytics Event

http
POST /v1/analytics/track

Request:

json
{
  "event_name": "page.view",
  "event_category": "navigation",
  "timestamp": "2026-02-17T10:00:00Z",
  "resource_type": "page",
  "resource_id": "treatment-plan-library",
  "page_url": "/library",
  "referrer_url": "/dashboard",
  "numeric_value": null,
  "properties": {
    "filter_condition": "neck_pain",
    "results_count": 12
  }
}

Response: 202 Accepted

Consent requirement: Level 2+ (analytics consent)


Pose Tracking

Track Pose Frame (Batch)

http
POST /v1/pose/frames

Accepts batched pose data (frontend buffers frames and sends every 1-2 seconds).

Request:

json
{
  "session_id": "550e8400-...",
  "media_id": "exercise-uuid-hashed",
  "frames": [
    {
      "frame_number": 450,
      "elapsed_ms": 15000,
      "landmark_x": [0.52, 0.51, 0.50, ...],
      "landmark_y": [0.32, 0.35, 0.38, ...],
      "landmark_z": [-0.1, -0.09, -0.08, ...],
      "landmark_visibility": [0.99, 0.98, 0.95, ...],
      "pose_confidence": 0.96,
      "landmarks_detected": 33,
      "rep_count": 5,
      "form_score": 0.85,
      "rom_degrees": 42.5,
      "active_exercise_phase": "concentric",
      "camera_resolution": "640x480",
      "processing_time_ms": 12
    }
  ]
}

Response: 202 Accepted

json
{
  "status": "accepted",
  "frames_accepted": 30,
  "session_id": "550e8400-..."
}

Consent requirement: Level 2+ (analytics consent — pose data is considered analytics, not essential)


Audit

Ingest Audit Entry

http
POST /v1/audit/ingest

Called internally by Core API middleware on every authenticated request. Not exposed to frontend.

Request:

json
{
  "action": "patient.view",
  "resource_type": "patient",
  "resource_id": "patient-123",
  "status": "success",
  "status_code": 200,
  "metadata": {
    "fields_accessed": ["name", "treatment_plans"]
  }
}

Headers enriched by middleware:

  • X-Request-Id — correlation ID
  • X-Actor-Hash — hashed user identity
  • X-Actor-Type — user, admin, specialist, system
  • X-Organization-Id — org context
  • X-Consent-Level — 0-3
  • X-Client-IP — real IP (via trusted proxy chain)

Response: 202 Accepted (async via audit-worker)


Error Tracking

Report Error

http
POST /v1/errors/report

Frontend reports errors for debugging. Support can correlate with patient complaints.

Request:

json
{
  "error_type": "video_error",
  "error_code": "MEDIA_ERR_NETWORK",
  "error_message": "Failed to load video segment",
  "feature_name": "video_player",
  "media_id": "exercise-uuid-hashed",
  "media_position_seconds": 23.5,
  "stack_trace": "Error: fetch failed at...",
  "response_time_ms": 30000,
  "memory_usage_mb": 245.6,
  "cpu_usage_percent": 78.3
}

Response: 202 Accepted

Consent requirement: Level 1+ (legitimate interest for customer support)


Admin

Update Geolocation Database

http
POST /v1/admin/geo/update

Triggers re-download of MaxMind GeoLite2 database. Admin only.

Response:

json
{
  "status": "updated",
  "database_version": "2026-02-15",
  "entries": 4200000
}

Get Geo Database Status

http
GET /v1/admin/geo/status

Response:

json
{
  "database_type": "GeoLite2-City",
  "build_date": "2026-02-15",
  "loaded": true,
  "entries": 4200000
}

Get Privacy Exclusions

http
GET /v1/admin/privacy/exclusions?page=1&per_page=50

Response:

json
{
  "exclusions": [
    {
      "id": "...",
      "ip_network": "198.51.100.0/24",
      "exclusion_type": "ccpa_do_not_sell",
      "is_active": true,
      "last_updated_by_maxmind": "2026-02-10T00:00:00Z"
    }
  ],
  "total": 2340,
  "page": 1,
  "per_page": 50
}

Sync Privacy Exclusions

http
POST /v1/admin/privacy/exclusions/sync

Triggers manual sync with MaxMind API (normally runs weekly via cron).

Response:

json
{
  "sync_batch_id": "...",
  "status": "running",
  "started_at": "2026-02-17T10:00:00Z"
}

Check IP Exclusion Status

http
GET /v1/admin/privacy/exclusions/check?ip=198.51.100.45

Response:

json
{
  "ip": "198.51.100.45",
  "is_excluded": true,
  "exclusion": {
    "type": "ccpa_do_not_sell",
    "network": "198.51.100.0/24",
    "legal_basis": "legal_obligation_ccpa"
  }
}

Dashboard (Internal)

Development/admin dashboard endpoints. Not exposed to patients.

MethodEndpointDescription
GET/dashboard/Dashboard home
GET/dashboard/auditAudit log viewer
GET/dashboard/analyticsAnalytics event viewer
GET/dashboard/mediaMedia session viewer
GET/dashboard/securitySecurity events viewer
GET/dashboard/detail/:type/:idDetailed entry view

Endpoint Summary

CategoryEndpointsConsent Level
Media Events3 (track, bandwidth stats, session stats)1+
Analytics1 (track)2+
Pose Tracking1 (batch frames)2+
Audit1 (ingest)Internal
Error Tracking1 (report)1+
Admin5 (geo, privacy)Admin only
Dashboard6 (viewers)Admin only
Total18