Content & Classes API
Browse and discover fitness content, manage live class schedules, and track user viewing sessions. All endpoints require the X-API-Key header. Endpoints marked with
Bearer
also require Authorization: Bearer <token>.
Content Discovery
Home Feed GET /content/discover Bearer
Get the home screen content feed. Returns structured sections for building the main app screen.
{
"success": true,
"data": {
"featured": [
{
"id": 1,
"name": "Morning HIIT Blast",
"thumbnailUrl": "https://...",
"trainer": { "name": "Coach Mike" },
"duration": 30,
"intensity": "high"
}
],
"continueWatching": [ ],
"upcomingLive": [ ],
"categories": [ ],
"newThisWeek": [ ]
}
}
Browse Classes GET /content/classes
Browse classes with filtering and pagination.
Class Detail GET /content/classes/:id
Get full class details including trainer information and related classes. Video URLs are not included in this response -- use GET /video/access/:classId when the user initiates playback.
{
"success": true,
"data": {
"class": {
"id": 42,
"name": "Morning HIIT Blast",
"description": "A high-energy 30-minute workout...",
"thumbnailUrl": "https://...",
"duration": 30,
"intensity": "high",
"isPremium": false,
"isVimeo": true,
"trainer": {
"id": 5,
"name": "Coach Mike",
"image": "https://..."
},
"category": {
"id": 2,
"name": "HIIT"
},
"relatedClasses": [
{ "id": 43, "name": "Evening HIIT", "duration": 25 }
]
}
}
}
Search GET /content/search
Full-text search across class names, descriptions, trainer names, and category names.
curl "https://api.studiostv.net/api/v1/content/search?q=yoga&limit=10" \
-H "X-API-Key: your-api-key"
const response = await fetch(
`${BASE_URL}/content/search?q=${encodeURIComponent(query)}&limit=10`,
{ headers: { 'X-API-Key': apiKey } }
);
const { data } = await response.json();
Categories GET /content/categories
List all active categories assigned to this client with class counts.
{
"success": true,
"data": {
"categories": [
{ "id": 1, "name": "Yoga", "classCount": 24, "image": "https://..." },
{ "id": 2, "name": "HIIT", "classCount": 18, "image": "https://..." },
{ "id": 3, "name": "Pilates", "classCount": 12, "image": "https://..." }
]
}
}
Class Browsing (Alternative)
An alternative set of class endpoints with a slightly different response structure, useful for building browse/discover pages.
Live Classes
Schedule GET /live/schedule
Get all upcoming live classes grouped by date.
{
"success": true,
"data": {
"schedule": {
"2026-03-01": [
{
"id": 10,
"name": "Live Yoga Flow",
"trainer": { "name": "Sarah" },
"scheduledTime": "09:00",
"duration": 60
}
],
"2026-03-02": [ ]
}
}
}
Add to My Schedule POST /live/schedule/:classId Bearer
Add a live class to the current user's schedule.
Remove from Schedule DELETE /live/schedule/:classId Bearer
Remove a live class from the current user's schedule.
My Schedule GET /live/my-schedule Bearer
Get the current user's scheduled live classes.
Video Access
Video URLs are never returned in class listing or detail endpoints. Instead, use the video access endpoint to request time-limited playback URLs when the user initiates playback.
Get Playback URLs GET /video/access/:classId Bearer
Returns both web embed URLs and native HLS stream URLs for the requested class. The endpoint validates that the authenticated user has access to the class through their client's category assignments.
{
"success": true,
"data": {
"embedUrl": "https://player.vimeo.com/video/710037770?h=063d88ffd5",
"streamUrl": "https://player.vimeo.com/play/.../hls?s=abc123&expires=1741536900",
"streamExpiresAt": "2026-03-09T18:15:00Z",
"introEmbedUrl": "https://player.vimeo.com/video/710037771?h=abc123",
"introStreamUrl": "https://player.vimeo.com/play/.../hls?s=def456&expires=1741536900",
"introStreamExpiresAt": "2026-03-09T18:15:00Z",
"token": "<signed-jwt>",
"expiresAt": "2026-03-09T12:15:00Z",
"isLive": false
}
}
{
"success": true,
"data": {
"embedUrl": "https://player.vimeo.com/video/...",
"streamUrl": "https://player.vimeo.com/play/.../hls?s=...",
"streamExpiresAt": "2026-03-09T20:00:00Z",
"token": "<signed-jwt>",
"expiresAt": "2026-03-09T14:00:00Z",
"isLive": true
}
}
The streamUrl expires naturally on Vimeo's side. If the user is in a long viewing session, monitor streamExpiresAt and re-request a fresh URL before it expires.
Session Tracking
Track user viewing progress for on-demand classes. Sessions persist progress so users can resume where they left off.
Start Session POST /sessions/start Bearer
Start a new viewing session. If the user already has an in-progress session for the same class, the existing session is returned.
{
"classId": 42,
"deviceType": "mobile"
}
{
"success": true,
"data": {
"session": {
"id": 1,
"classId": 42,
"userId": 1,
"status": "in_progress",
"progressSeconds": 0,
"startedAt": "2026-02-28T10:00:00Z"
}
}
}
Update Progress POST /sessions/:id/progress Bearer
Send progress updates. Call this every ~30 seconds from the client player.
{
"progressSeconds": 540,
"totalDurationSeconds": 1800,
"castingMethod": "chromecast"
}
Auto-completion
Sessions automatically complete at 90% progress. You do not need to explicitly call the complete endpoint in most cases.
Complete Session POST /sessions/:id/complete Bearer
Manually mark a viewing session as complete.
Viewing History GET /sessions/history Bearer
Get the user's viewing history with class details and progress percentages.
App Strings GET /app/strings
Get client-specific content strings such as About Us and Privacy Policy. These are HTML strings managed by partners via the Partner Portal.
Auth: X-API-Key required
{
"success": true,
"data": [
{
"st_aboutus": "<h1>About Us</h1><p>Content...</p>",
"st_privacypolicy": "<h1>Privacy Policy</h1><p>Policy...</p>"
}
]
}
Render the HTML in a WebView or HTML renderer. Fetch once and cache locally.
Products GET /products
Browse affiliate products created by the partner. Only returns products with status active.
Auth: X-API-Key required
List Products GET /products
{
"success": true,
"data": {
"products": [
{
"id": "uuid",
"name": "Protein Powder",
"description": "Premium whey protein...",
"image": "https://...",
"price": "29.99",
"currency": "USD",
"externalUrl": "https://shop.example.com/protein",
"productType": "Supplements",
"featured": true,
"status": "active",
"sortOrder": 0
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 5,
"totalPages": 1
}
}
}
Product Detail GET /products/:id
Get a single product by ID. The externalUrl field should be opened in an external browser for the "Buy Now" action.
Product Types GET /products/types
List distinct product types for the current client with counts. Use to build category/filter navigation in the store.
{
"success": true,
"data": [
{ "productType": "Apparel", "count": 3 },
{ "productType": "Supplements", "count": 5 }
]
}
Building a Content Experience
Here is a recommended approach for building a content-driven app:
Call GET /content/discover to populate the home screen with featured content, continue watching, and upcoming live classes. This single endpoint provides everything needed for the main screen.
Use GET /content/classes with filter parameters to build a browsable catalogue. Fetch categories with GET /content/categories for the filter UI.
When a user taps play, call GET /video/access/:classId to get time-limited playback URLs (streamUrl for mobile, embedUrl for web). Then call POST /sessions/start to create or resume a session. Send progress heartbeats every 30 seconds with POST /sessions/:id/progress. The session auto-completes at 90%.
Wire up GET /content/search?q= to a search bar. Results span classes, trainers, and categories.