# Content API

The KinesteX Content API provides access to workout plans, individual workouts, and exercises. Use it to build custom content browsers, create personalized workout recommendations, or integrate KinesteX content into your app.

**SDK vs REST API:**
- **Swift, Kotlin, Flutter**: Use the built-in SDK convenience methods (recommended)
- **React Native, React TypeScript, HTML/JS**: Use direct REST API calls

**Base URL:** `https://admin.kinestex.com/api/v1/`

**Available Endpoints:**
| Endpoint | Description |
|----------|-------------|
| /workouts | Fetch workout content |
| /plans | Fetch workout plan content |
| /exercises | Fetch exercise content |

**Headers (REST API only):**
| Header | Description |
|--------|-------------|
| x-api-key | Your API key for authentication |
| x-company-name | The name of your company |

## Getting Started

Before using the Content API, ensure your SDK is properly initialized. The API methods are only available after initialization.

**For SDK platforms (Swift, Kotlin, Flutter):** Initialize the SDK with your credentials
**For REST platforms (React Native, React TypeScript, HTML/JS):** Set up your request headers

**Initialize SDK / Setup Headers**

_Swift (iOS)_
```swift
import KinesteXAIKit

// Initialize KinesteXAIKit with your credentials
let kinestex = KinesteXAIKit(
    apiKey: "YOUR_API_KEY",
    companyName: "YOUR_COMPANY",
    userId: "user_123"
)

// Now you can use the Content API methods:
// - kinestex.fetchWorkouts()
// - kinestex.fetchPlans()
// - kinestex.fetchExercises()
// - kinestex.fetchWorkout(id:)
// - kinestex.fetchPlan(id:)
// - kinestex.fetchExercise(id:)
// - kinestex.fetchContent(contentType:, ...)
```

_Kotlin (Android)_
```kotlin
import com.kinestex.kinestexsdkkotlin.KinesteXSDK

// SDK must be initialized before using Content API
// This is typically done in your Application class or Activity

// Access Content API through KinesteXSDK.api
// Available method:
// KinesteXSDK.api.fetchAPIContentData(
//     contentType: ContentType,
//     id: String? = null,
//     title: String? = null,
//     category: String? = null,
//     bodyParts: List<BodyPart>? = null,
//     lastDocId: String? = null,
//     limit: Int? = null
// ): APIContentResult
```

_Flutter_
```dart
import 'package:kinestex_sdk_flutter/kinestex_sdk.dart';

// Initialize the SDK before using Content API
await KinesteXAIFramework.initialize(
  apiKey: "YOUR_API_KEY",
  companyName: "YOUR_COMPANY",
  userId: "user_123",
);

// Access Content API through:
// KinesteXAIFramework.apiService.fetchContent(...)
```

_React Native_
```jsx
// Set up headers for REST API calls
const API_KEY = 'YOUR_API_KEY';
const COMPANY_NAME = 'YOUR_COMPANY';
const BASE_URL = 'https://admin.kinestex.com/api/v1';

const headers = {
  'x-api-key': API_KEY,
  'x-company-name': COMPANY_NAME,
};

// Use these headers in all fetch requests
```

_HTML / JavaScript_
```html
// Set up headers for REST API calls
const API_KEY = 'YOUR_API_KEY';
const COMPANY_NAME = 'YOUR_COMPANY';
const BASE_URL = 'https://admin.kinestex.com/api/v1';

const headers = {
  'x-api-key': API_KEY,
  'x-company-name': COMPANY_NAME,
};

// Use these headers in all fetch requests
```

_React (TypeScript)_
```tsx
// Set up headers for REST API calls
const API_KEY = 'YOUR_API_KEY';
const COMPANY_NAME = 'YOUR_COMPANY';
const BASE_URL = 'https://admin.kinestex.com/api/v1';

const headers: HeadersInit = {
  'x-api-key': API_KEY,
  'x-company-name': COMPANY_NAME,
};

// TypeScript interfaces for API responses
interface WorkoutModel {
  id: string;
  title: string;
  category: string;
  calories: number;
  total_minutes: number;
  body_parts: string[];
  dif_level: string;
  description: string;
  workout_desc_img: string;
  sequence: ExerciseModel[];
}

interface ExerciseModel {
  id: string;
  title: string;
  body_parts: string[];
  video_url: string;
  thumbnail_url: string;
  model_id: string;
}

interface PlanModel {
  id: string;
  title: string;
  img_url: string;
  category: Record<string, any>;
  levels: Record<string, any>;
}
```

**Available SDK Methods** — Swift (iOS)

KinesteXAIKit provides convenient methods that handle all the complexity of API calls for you.

_Convenience Methods (Recommended)_
```swift
// Fetch lists with optional filters
func fetchWorkouts(category: String? = nil, bodyParts: [BodyPart]? = nil, limit: Int? = 10, lastDocId: String? = nil, lang: String = "en") async -> Result<WorkoutsResponse, Error>

func fetchExercises(bodyParts: [BodyPart]? = nil, limit: Int? = 10, lastDocId: String? = nil, lang: String = "en") async -> Result<ExercisesResponse, Error>

func fetchPlans(category: String? = nil, limit: Int? = 10, lastDocId: String? = nil, lang: String = "en") async -> Result<PlansResponse, Error>

// Fetch single items by ID
func fetchWorkout(id: String, lang: String = "en") async -> Result<WorkoutModel, Error>
func fetchExercise(id: String, lang: String = "en") async -> Result<ExerciseModel, Error>
func fetchPlan(id: String, lang: String = "en") async -> Result<PlanModel, Error>
```

_Advanced Method (Full Control)_
```swift
// Use fetchContent for advanced filtering or when you need the raw result type
func fetchContent(
    contentType: ContentType,  // .workout, .plan, .exercise
    id: String? = nil,
    title: String? = nil,
    lang: String = "en",
    category: String? = nil,
    bodyParts: [BodyPart]? = nil,
    lastDocId: String? = nil,
    limit: Int? = nil
) async -> APIContentResult
```

**ContentType Enum** — Kotlin (Android)

Use these values to specify what type of content to fetch.

_Available Content Types_
```kotlin
enum class ContentType {
    WORKOUT,  // Fetch workouts
    PLAN,     // Fetch workout plans
    EXERCISE  // Fetch exercises
}
```

**ContentType Enum** — Flutter

Use these values to specify what type of content to fetch.

_Available Content Types_
```dart
enum ContentType {
  workout,   // Fetch workouts
  plan,      // Fetch workout plans
  exercise   // Fetch exercises
}
```

## Fetching Content Lists

Fetch lists of workouts, plans, or exercises with optional filtering.

**Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| category | String | Filter by category. **Required for plans** in Flutter, Swift, and Kotlin SDKs. Optional for workouts and exercises. |
| bodyParts | [BodyPart] | Filter by targeted body parts (optional) |
| include_kinestex | Bool | Include KinesteX workout library in results (default: true) |
| limit | Int | Number of results to return (default: 10) |
| lang | String | Language code (default: "en") |
| lastDocId | String | For pagination (optional) |
| translation_languages | String | Filter by available translations. Comma-separated language codes (e.g. "es,fr") or repeated query parameters (optional, REST API only) |

**Fetch Workouts**

_Swift (iOS)_
```swift
// Fetch workouts with optional filters
Task {
    let result = await kinestex.fetchWorkouts(
        category: "Fitness",  // or "Rehabilitation"
        limit: 10
    )

    switch result {
    case .success(let response):
        let workouts = response.workouts
        print("Fetched \(workouts.count) workouts")

        for workout in workouts {
            print("- \(workout.title): \(workout.totalMinutes ?? 0) mins")
        }

        // Store lastDocId for pagination
        let nextPageId = response.lastDocId

    case .failure(let error):
        print("Error: \(error.localizedDescription)")
    }
}
```

_Kotlin (Android)_
```kotlin
// Fetch workouts using coroutines
lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) {
        KinesteXSDK.api.fetchAPIContentData(
            contentType = ContentType.WORKOUT,
            category = "Fitness",  // or "Rehabilitation"
            limit = 10
        )
    }

    when (result) {
        is APIContentResult.Workouts -> {
            val workouts = result.workouts
            Log.d("API", "Fetched ${workouts.size} workouts")

            workouts.forEach { workout ->
                Log.d("API", "- ${workout.title}")
            }

            // Store lastDocId for pagination
            val nextPageId = result.lastDocId
        }
        is APIContentResult.Error -> {
            Log.e("API", "Error: ${result.message}")
        }
        else -> {
            Log.w("API", "Unexpected result type")
        }
    }
}
```

_Flutter_
```dart
// Fetch workouts
Future<void> fetchWorkouts() async {
  final result = await KinesteXAIFramework.apiService.fetchContent(
    contentType: ContentType.workout,
    category: "Fitness",  // or "Rehabilitation"
    limit: 10,
  );

  switch (result) {
    case WorkoutsResult(:final response):
      final workouts = response.workouts;
      print('Fetched ${workouts.length} workouts');

      for (final workout in workouts) {
        print('- ${workout.title}');
      }

      // Store lastDocId for pagination
      final nextPageId = response.lastDocId;

    case ErrorResult(:final message):
      print('Error: $message');

    default:
      print('Unexpected result type');
  }
}
```

_React Native_
```jsx
// Fetch workouts using fetch API
const fetchWorkouts = async (
  category?: string,
  limit: number = 10
): Promise<WorkoutModel[]> => {
  const params = new URLSearchParams({
    limit: String(limit),
  });

  if (category) {
    params.append('category', category);
  }

  const response = await fetch(
    `${BASE_URL}/workouts?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  const data = await response.json();
  return data.workouts;
};

// Usage
const workouts = await fetchWorkouts('Fitness', 10);
console.log(`Fetched ${workouts.length} workouts`);
```

_HTML / JavaScript_
```html
// Fetch workouts using fetch API
async function fetchWorkouts(category, limit = 10) {
  const params = new URLSearchParams({ limit: String(limit) });

  if (category) {
    params.append('category', category);
  }

  const response = await fetch(
    `${BASE_URL}/workouts?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  const data = await response.json();
  return data.workouts;
}

// Usage
fetchWorkouts('Fitness', 10)
  .then(workouts => console.log(`Fetched ${workouts.length} workouts`))
  .catch(error => console.error('Error:', error));
```

_React (TypeScript)_
```tsx
// Fetch workouts with TypeScript
interface WorkoutsResponse {
  workouts: WorkoutModel[];
  lastDocId?: string;
}

const fetchWorkouts = async (
  category?: string,
  limit: number = 10
): Promise<WorkoutsResponse> => {
  const params = new URLSearchParams({
    limit: String(limit),
  });

  if (category) {
    params.append('category', category);
  }

  const response = await fetch(
    `${BASE_URL}/workouts?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
};

// Usage
const { workouts, lastDocId } = await fetchWorkouts('Fitness', 10);
console.log(`Fetched ${workouts.length} workouts`);
```

**Fetch Plans**

_Swift (iOS)_
```swift
// Fetch workout plans
Task {
    let result = await kinestex.fetchPlans(
        category: "Strength",  // Rehabilitation, Weight Management, Cardio, Strength
        limit: 5
    )

    switch result {
    case .success(let response):
        let plans = response.plans
        print("Fetched \(plans.count) plans")

    case .failure(let error):
        print("Error: \(error.localizedDescription)")
    }
}
```

_Kotlin (Android)_
```kotlin
// Fetch workout plans
// IMPORTANT: Always provide 'category' when fetching plans.
lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) {
        KinesteXSDK.api.fetchAPIContentData(
            contentType = ContentType.PLAN,
            category = "Strength",  // Required: Rehabilitation, Weight Management, Cardio, Strength
            limit = 5
        )
    }

    when (result) {
        is APIContentResult.Plans -> {
            val plans = result.plans
            Log.d("API", "Fetched ${plans.size} plans")
        }
        is APIContentResult.Error -> {
            Log.e("API", "Error: ${result.message}")
        }
        else -> {}
    }
}
```

_Flutter_
```dart
// Fetch workout plans
// IMPORTANT: Always provide 'category' when fetching plans.
// If category is null, the SDK may interpret the response as a single PlanResult
// instead of PlansResult (list).
Future<void> fetchPlans() async {
  final result = await KinesteXAIFramework.apiService.fetchContent(
    contentType: ContentType.plan,
    category: "Strength",  // Required: Rehabilitation, Weight Management, Cardio, Strength
    limit: 5,
  );

  switch (result) {
    case PlansResult(:final response):
      final plans = response.plans;
      print('Fetched ${plans.length} plans');

    case ErrorResult(:final message):
      print('Error: $message');

    default:
      break;
  }
}
```

_React Native_
```jsx
// Fetch workout plans
const fetchPlans = async (
  category?: string,
  limit: number = 5
): Promise<PlanModel[]> => {
  const params = new URLSearchParams({ limit: String(limit) });

  if (category) {
    params.append('category', category);
  }

  const response = await fetch(
    `${BASE_URL}/plans?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  const data = await response.json();
  return data.plans;
};

// Usage - Plan categories: Rehabilitation, Weight Management, Cardio, Strength
const plans = await fetchPlans('Strength', 5);
```

_HTML / JavaScript_
```html
// Fetch workout plans
async function fetchPlans(category, limit = 5) {
  const params = new URLSearchParams({ limit: String(limit) });

  if (category) {
    params.append('category', category);
  }

  const response = await fetch(
    `${BASE_URL}/plans?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  const data = await response.json();
  return data.plans;
}

// Usage - Plan categories: Rehabilitation, Weight Management, Cardio, Strength
fetchPlans('Strength', 5).then(plans => console.log(plans));
```

_React (TypeScript)_
```tsx
// Fetch workout plans
interface PlansResponse {
  plans: PlanModel[];
  lastDocId?: string;
}

const fetchPlans = async (
  category?: string,
  limit: number = 5
): Promise<PlansResponse> => {
  const params = new URLSearchParams({ limit: String(limit) });

  if (category) {
    params.append('category', category);
  }

  const response = await fetch(
    `${BASE_URL}/plans?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
};

// Usage - Plan categories: Rehabilitation, Weight Management, Cardio, Strength
const { plans } = await fetchPlans('Strength', 5);
```

**Fetch Exercises**

_Swift (iOS)_
```swift
// Fetch exercises filtered by body parts
Task {
    let result = await kinestex.fetchExercises(
        bodyParts: [.abs, .glutes],
        limit: 10
    )

    switch result {
    case .success(let response):
        let exercises = response.exercises
        print("Fetched \(exercises.count) exercises")

        for exercise in exercises {
            print("- \(exercise.title): \(exercise.bodyParts.joined(separator: ", "))")
        }

    case .failure(let error):
        print("Error: \(error.localizedDescription)")
    }
}
```

_Kotlin (Android)_
```kotlin
// Fetch exercises filtered by body parts
lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) {
        KinesteXSDK.api.fetchAPIContentData(
            contentType = ContentType.EXERCISE,
            bodyParts = listOf(BodyPart.ABS, BodyPart.GLUTES),
            limit = 10
        )
    }

    when (result) {
        is APIContentResult.Exercises -> {
            val exercises = result.exercises
            Log.d("API", "Fetched ${exercises.size} exercises")

            exercises.forEach { exercise ->
                Log.d("API", "- ${exercise.title}")
            }
        }
        is APIContentResult.Error -> {
            Log.e("API", "Error: ${result.message}")
        }
        else -> {}
    }
}
```

_Flutter_
```dart
// Fetch exercises filtered by body parts
Future<void> fetchExercises() async {
  final result = await KinesteXAIFramework.apiService.fetchContent(
    contentType: ContentType.exercise,
    bodyParts: [BodyPart.abs, BodyPart.glutes],
    limit: 10,
  );

  switch (result) {
    case ExercisesResult(:final response):
      final exercises = response.exercises;
      print('Fetched ${exercises.length} exercises');

      for (final exercise in exercises) {
        print('- ${exercise.title}');
      }

    case ErrorResult(:final message):
      print('Error: $message');

    default:
      break;
  }
}
```

_React Native_
```jsx
// Fetch exercises filtered by body parts
const fetchExercises = async (
  bodyParts?: string[],
  limit: number = 10
): Promise<ExerciseModel[]> => {
  const params = new URLSearchParams({ limit: String(limit) });

  if (bodyParts && bodyParts.length > 0) {
    params.append('body_parts', bodyParts.join(','));
  }

  const response = await fetch(
    `${BASE_URL}/exercises?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  const data = await response.json();
  return data.exercises;
};

// Usage
const exercises = await fetchExercises(['Abs', 'Glutes'], 10);
```

_HTML / JavaScript_
```html
// Fetch exercises filtered by body parts
async function fetchExercises(bodyParts, limit = 10) {
  const params = new URLSearchParams({ limit: String(limit) });

  if (bodyParts && bodyParts.length > 0) {
    params.append('body_parts', bodyParts.join(','));
  }

  const response = await fetch(
    `${BASE_URL}/exercises?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  const data = await response.json();
  return data.exercises;
}

// Usage
fetchExercises(['Abs', 'Glutes'], 10).then(exercises => console.log(exercises));
```

_React (TypeScript)_
```tsx
// Fetch exercises filtered by body parts
interface ExercisesResponse {
  exercises: ExerciseModel[];
  lastDocId?: string;
}

const fetchExercises = async (
  bodyParts?: string[],
  limit: number = 10
): Promise<ExercisesResponse> => {
  const params = new URLSearchParams({ limit: String(limit) });

  if (bodyParts && bodyParts.length > 0) {
    params.append('body_parts', bodyParts.join(','));
  }

  const response = await fetch(
    `${BASE_URL}/exercises?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
};

// Usage
const { exercises } = await fetchExercises(['Abs', 'Glutes'], 10);
```

## Fetching Single Items

Fetch a specific workout, plan, or exercise by ID or title.

**By ID:** Use the unique document ID for exact match
**By Title:** Use the content title (case-insensitive, returns first match)

**Fetch by ID**

_Swift (iOS)_
```swift
// Fetch a specific workout by ID
Task {
    let result = await kinestex.fetchWorkout(id: "9zE1kzOzpU5d5dAJrPOY")

    switch result {
    case .success(let workout):
        print("Workout: \(workout.title)")
        print("Duration: \(workout.totalMinutes ?? 0) minutes")
        print("Calories: \(workout.totalCalories ?? 0)")
        print("Exercises: \(workout.sequence.count)")

    case .failure(let error):
        print("Error: \(error.localizedDescription)")
    }
}

// Fetch a specific exercise by ID
Task {
    let result = await kinestex.fetchExercise(id: "jz73VFlUyZ9nyd64OjRb")

    switch result {
    case .success(let exercise):
        print("Exercise: \(exercise.title)")
        print("Model ID: \(exercise.modelId)")

    case .failure(let error):
        print("Error: \(error.localizedDescription)")
    }
}

// Fetch a specific plan by ID
Task {
    let result = await kinestex.fetchPlan(id: "22B3qRU2r75hVXHgGiGx")

    switch result {
    case .success(let plan):
        print("Plan: \(plan.title)")

    case .failure(let error):
        print("Error: \(error.localizedDescription)")
    }
}
```

_Kotlin (Android)_
```kotlin
// Fetch a specific workout by ID
lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) {
        KinesteXSDK.api.fetchAPIContentData(
            contentType = ContentType.WORKOUT,
            id = "9zE1kzOzpU5d5dAJrPOY"
        )
    }

    when (result) {
        is APIContentResult.Workout -> {
            val workout = result.workout
            Log.d("API", "Workout: ${workout.title}")
            Log.d("API", "Duration: ${workout.totalMinutes} minutes")
        }
        is APIContentResult.Error -> {
            Log.e("API", "Error: ${result.message}")
        }
        else -> {}
    }
}

// Fetch a specific exercise by ID
lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) {
        KinesteXSDK.api.fetchAPIContentData(
            contentType = ContentType.EXERCISE,
            id = "jz73VFlUyZ9nyd64OjRb"
        )
    }

    when (result) {
        is APIContentResult.Exercise -> {
            val exercise = result.exercise
            Log.d("API", "Exercise: ${exercise.title}")
        }
        is APIContentResult.Error -> {
            Log.e("API", "Error: ${result.message}")
        }
        else -> {}
    }
}
```

_Flutter_
```dart
// Fetch a specific workout by ID
Future<void> fetchWorkoutById() async {
  final result = await KinesteXAIFramework.apiService.fetchContent(
    contentType: ContentType.workout,
    id: "9zE1kzOzpU5d5dAJrPOY",
  );

  switch (result) {
    case WorkoutResult(:final workout):
      print('Workout: ${workout.title}');
      print('Duration: ${workout.totalMinutes} minutes');
      print('Exercises: ${workout.sequence.length}');

    case ErrorResult(:final message):
      print('Error: $message');

    default:
      break;
  }
}

// Fetch a specific exercise by ID
Future<void> fetchExerciseById() async {
  final result = await KinesteXAIFramework.apiService.fetchContent(
    contentType: ContentType.exercise,
    id: "jz73VFlUyZ9nyd64OjRb",
  );

  switch (result) {
    case ExerciseResult(:final exercise):
      print('Exercise: ${exercise.title}');
      print('Model ID: ${exercise.modelId}');

    case ErrorResult(:final message):
      print('Error: $message');

    default:
      break;
  }
}
```

_React Native_
```jsx
// Fetch a specific workout by ID
const fetchWorkoutById = async (id: string): Promise<WorkoutModel> => {
  const response = await fetch(
    `${BASE_URL}/workouts/${id}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
};

// Fetch a specific exercise by ID
const fetchExerciseById = async (id: string): Promise<ExerciseModel> => {
  const response = await fetch(
    `${BASE_URL}/exercises/${id}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
};

// Fetch a specific plan by ID
const fetchPlanById = async (id: string): Promise<PlanModel> => {
  const response = await fetch(
    `${BASE_URL}/plans/${id}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
};

// Usage
const workout = await fetchWorkoutById('9zE1kzOzpU5d5dAJrPOY');
const exercise = await fetchExerciseById('jz73VFlUyZ9nyd64OjRb');
const plan = await fetchPlanById('22B3qRU2r75hVXHgGiGx');
```

_HTML / JavaScript_
```html
// Fetch a specific workout by ID
async function fetchWorkoutById(id) {
  const response = await fetch(
    `${BASE_URL}/workouts/${id}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
}

// Fetch a specific exercise by ID
async function fetchExerciseById(id) {
  const response = await fetch(
    `${BASE_URL}/exercises/${id}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
}

// Fetch a specific plan by ID
async function fetchPlanById(id) {
  const response = await fetch(
    `${BASE_URL}/plans/${id}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
}

// Usage
fetchWorkoutById('9zE1kzOzpU5d5dAJrPOY').then(workout => console.log(workout));
```

_React (TypeScript)_
```tsx
// Fetch a specific workout by ID
const fetchWorkoutById = async (id: string): Promise<WorkoutModel> => {
  const response = await fetch(
    `${BASE_URL}/workouts/${id}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
};

// Fetch a specific exercise by ID
const fetchExerciseById = async (id: string): Promise<ExerciseModel> => {
  const response = await fetch(
    `${BASE_URL}/exercises/${id}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
};

// Fetch a specific plan by ID
const fetchPlanById = async (id: string): Promise<PlanModel> => {
  const response = await fetch(
    `${BASE_URL}/plans/${id}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
};

// Usage
const workout = await fetchWorkoutById('9zE1kzOzpU5d5dAJrPOY');
console.log(`Workout: ${workout.title}`);
```

**Fetch by Title**

_Swift (iOS)_
```swift
// Fetch content by title (returns first match)
Task {
    let result = await kinestex.fetchContent(
        contentType: .workout,
        title: "Fitness Lite"
    )

    switch result {
    case .workout(let workout):
        print("Found workout: \(workout.title)")

    case .error(let message):
        print("Error: \(message)")

    default:
        print("Unexpected result type")
    }
}
```

_Kotlin (Android)_
```kotlin
// Fetch content by title (returns first match)
lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) {
        KinesteXSDK.api.fetchAPIContentData(
            contentType = ContentType.WORKOUT,
            title = "Fitness Lite"
        )
    }

    when (result) {
        is APIContentResult.Workout -> {
            Log.d("API", "Found workout: ${result.workout.title}")
        }
        is APIContentResult.Error -> {
            Log.e("API", "Error: ${result.message}")
        }
        else -> {}
    }
}
```

_Flutter_
```dart
// Fetch content by title (returns first match)
Future<void> fetchByTitle() async {
  final result = await KinesteXAIFramework.apiService.fetchContent(
    contentType: ContentType.workout,
    title: "Fitness Lite",
  );

  switch (result) {
    case WorkoutResult(:final workout):
      print('Found workout: ${workout.title}');

    case ErrorResult(:final message):
      print('Error: $message');

    default:
      break;
  }
}
```

_React Native_
```jsx
// Fetch content by title (returns first match)
const fetchWorkoutByTitle = async (title: string): Promise<WorkoutModel> => {
  const response = await fetch(
    `${BASE_URL}/workouts/${encodeURIComponent(title)}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
};

// Usage
const workout = await fetchWorkoutByTitle('Fitness Lite');
```

_HTML / JavaScript_
```html
// Fetch content by title (returns first match)
async function fetchWorkoutByTitle(title) {
  const response = await fetch(
    `${BASE_URL}/workouts/${encodeURIComponent(title)}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
}

// Usage
fetchWorkoutByTitle('Fitness Lite').then(workout => console.log(workout));
```

_React (TypeScript)_
```tsx
// Fetch content by title (returns first match)
const fetchWorkoutByTitle = async (title: string): Promise<WorkoutModel> => {
  const response = await fetch(
    `${BASE_URL}/workouts/${encodeURIComponent(title)}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  return response.json();
};

// Usage
const workout = await fetchWorkoutByTitle('Fitness Lite');
```

## Filtering & Parameters

Filter content by category and body parts for targeted results.

**Workout Categories:** Fitness, Rehabilitation

**Plan Categories:** Rehabilitation, Weight Management, Cardio, Strength

> **Important (Flutter, Swift & Kotlin SDKs):** When fetching plans, always provide the `category` parameter.

**Include KinesteX Library:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| include_kinestex | Bool | true | When set to `true`, results include workouts, plans, and exercises from the KinesteX workout library. Set to `false` to exclude KinesteX library content and only return your own custom content. |

**Filter by Translation Languages (REST API):**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| translation_languages | String | — | Filter content by available translations. Pass a comma-separated list of language codes (e.g. `es,fr`) or repeat the parameter for each language (e.g. `translation_languages=es&translation_languages=fr`). Only content with translations in **all** specified languages is returned. Optional — omit to return all content regardless of translations. |

**Body Parts (BodyPart enum):**
| SDK Value (Swift) | SDK Value (Kotlin) | SDK Value (Flutter) | REST API Value |
|-------------------|--------------------|--------------------|----------------|
| .abs | ABS | BodyPart.abs | Abs |
| .biceps | BICEPS | BodyPart.biceps | Biceps |
| .calves | CALVES | BodyPart.calves | Calves |
| .chest | CHEST | BodyPart.chest | Chest |
| .externalOblique | EXTERNAL_OBLIQUE | BodyPart.externalOblique | External Oblique |
| .forearms | FOREARMS | BodyPart.forearms | Forearms |
| .glutes | GLUTES | BodyPart.glutes | Glutes |
| .hamstrings | HAMSTRINGS | BodyPart.hamstrings | Hamstrings |
| .lats | LATS | BodyPart.lats | Lats |
| .lowerBack | LOWER_BACK | BodyPart.lowerBack | Lower Back |
| .neck | NECK | BodyPart.neck | Neck |
| .quads | QUADS | BodyPart.quads | Quads |
| .shoulders | SHOULDERS | BodyPart.shoulders | Shoulders |
| .traps | TRAPS | BodyPart.traps | Traps |
| .triceps | TRICEPS | BodyPart.triceps | Triceps |
| .fullBody | FULL_BODY | BodyPart.fullBody | Full Body |

**Filter by Category and Body Parts**

_Swift (iOS)_
```swift
// Combine category and body parts filters
Task {
    let result = await kinestex.fetchContent(
        contentType: .workout,
        category: "Fitness",
        bodyParts: [.abs, .glutes, .quads],
        limit: 10
    )

    switch result {
    case .workouts(let response):
        let workouts = response.workouts
        print("Found \(workouts.count) workouts targeting abs, glutes, and quads")

    case .error(let message):
        print("Error: \(message)")

    default:
        break
    }
}
```

_Kotlin (Android)_
```kotlin
// Combine category and body parts filters
lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) {
        KinesteXSDK.api.fetchAPIContentData(
            contentType = ContentType.WORKOUT,
            category = "Fitness",
            bodyParts = listOf(BodyPart.ABS, BodyPart.GLUTES, BodyPart.QUADS),
            limit = 10
        )
    }

    when (result) {
        is APIContentResult.Workouts -> {
            val workouts = result.workouts
            Log.d("API", "Found ${workouts.size} workouts")
        }
        is APIContentResult.Error -> {
            Log.e("API", "Error: ${result.message}")
        }
        else -> {}
    }
}
```

_Flutter_
```dart
// Combine category and body parts filters
Future<void> fetchFilteredWorkouts() async {
  final result = await KinesteXAIFramework.apiService.fetchContent(
    contentType: ContentType.workout,
    category: "Fitness",
    bodyParts: [BodyPart.abs, BodyPart.glutes, BodyPart.quads],
    limit: 10,
  );

  switch (result) {
    case WorkoutsResult(:final response):
      print('Found ${response.workouts.length} workouts');

    case ErrorResult(:final message):
      print('Error: $message');

    default:
      break;
  }
}
```

_React Native_
```jsx
// Combine category and body parts filters
const fetchFilteredWorkouts = async (
  category: string,
  bodyParts: string[],
  limit: number = 10
): Promise<WorkoutModel[]> => {
  const params = new URLSearchParams({
    category,
    body_parts: bodyParts.join(','),
    limit: String(limit),
  });

  const response = await fetch(
    `${BASE_URL}/workouts?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  const data = await response.json();
  return data.workouts;
};

// Usage
const workouts = await fetchFilteredWorkouts(
  'Fitness',
  ['Abs', 'Glutes', 'Quads'],
  10
);
```

_HTML / JavaScript_
```html
// Combine category and body parts filters
async function fetchFilteredWorkouts(category, bodyParts, limit = 10) {
  const params = new URLSearchParams({
    category,
    body_parts: bodyParts.join(','),
    limit: String(limit),
  });

  const response = await fetch(
    `${BASE_URL}/workouts?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  const data = await response.json();
  return data.workouts;
}

// Usage
fetchFilteredWorkouts('Fitness', ['Abs', 'Glutes', 'Quads'], 10)
  .then(workouts => console.log(workouts));
```

_React (TypeScript)_
```tsx
// Combine category and body parts filters
const fetchFilteredWorkouts = async (
  category: string,
  bodyParts: string[],
  limit: number = 10
): Promise<WorkoutModel[]> => {
  const params = new URLSearchParams({
    category,
    body_parts: bodyParts.join(','),
    limit: String(limit),
  });

  const response = await fetch(
    `${BASE_URL}/workouts?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  const data = await response.json();
  return data.workouts;
};

// Usage
const workouts = await fetchFilteredWorkouts(
  'Fitness',
  ['Abs', 'Glutes', 'Quads'],
  10
);
```

**Exclude KinesteX Library Content**

_Swift (iOS)_
```swift
// Fetch only your custom workouts (exclude KinesteX library)
Task {
    let result = await kinestex.fetchWorkouts(
        category: "Fitness",
        includeKinestex: false,  // Exclude KinesteX library content
        limit: 10
    )

    switch result {
    case .success(let response):
        let workouts = response.workouts
        print("Fetched \(workouts.count) custom workouts")

    case .failure(let error):
        print("Error: \(error.localizedDescription)")
    }
}
```

_Kotlin (Android)_
```kotlin
// Fetch only your custom workouts (exclude KinesteX library)
lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) {
        KinesteXSDK.api.fetchAPIContentData(
            contentType = ContentType.WORKOUT,
            category = "Fitness",
            includeKinestex = false,  // Exclude KinesteX library content
            limit = 10
        )
    }

    when (result) {
        is APIContentResult.Workouts -> {
            val workouts = result.workouts
            Log.d("API", "Fetched ${workouts.size} custom workouts")
        }
        is APIContentResult.Error -> {
            Log.e("API", "Error: ${result.message}")
        }
        else -> {}
    }
}
```

_Flutter_
```dart
// Fetch only your custom workouts (exclude KinesteX library)
Future<void> fetchCustomWorkouts() async {
  final result = await KinesteXAIFramework.apiService.fetchContent(
    contentType: ContentType.workout,
    category: "Fitness",
    queryParameters: {'include_kinestex': false}, // Exclude KinesteX library content
    limit: 10,
  );

  switch (result) {
    case WorkoutsResult(:final response):
      print('Fetched ${response.workouts.length} custom workouts');

    case ErrorResult(:final message):
      print('Error: $message');

    default:
      break;
  }
}
```

_React Native_
```jsx
// Fetch only your custom workouts (exclude KinesteX library)
const fetchCustomWorkouts = async (
  category: string,
  limit: number = 10
): Promise<WorkoutModel[]> => {
  const params = new URLSearchParams({
    category,
    include_kinestex: 'false',  // Exclude KinesteX library content
    limit: String(limit),
  });

  const response = await fetch(
    `${BASE_URL}/workouts?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  const data = await response.json();
  return data.workouts;
};

// Usage - returns only your custom content
const customWorkouts = await fetchCustomWorkouts('Fitness', 10);
```

_HTML / JavaScript_
```html
// Fetch only your custom workouts (exclude KinesteX library)
async function fetchCustomWorkouts(category, limit = 10) {
  const params = new URLSearchParams({
    category,
    include_kinestex: 'false',  // Exclude KinesteX library content
    limit: String(limit),
  });

  const response = await fetch(
    `${BASE_URL}/workouts?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  const data = await response.json();
  return data.workouts;
}

// Usage - returns only your custom content
fetchCustomWorkouts('Fitness', 10)
  .then(workouts => console.log(workouts));
```

_React (TypeScript)_
```tsx
// Fetch only your custom workouts (exclude KinesteX library)
const fetchCustomWorkouts = async (
  category: string,
  limit: number = 10
): Promise<WorkoutModel[]> => {
  const params = new URLSearchParams({
    category,
    include_kinestex: 'false',  // Exclude KinesteX library content
    limit: String(limit),
  });

  const response = await fetch(
    `${BASE_URL}/workouts?${params}`,
    { headers }
  );

  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }

  const data = await response.json();
  return data.workouts;
};

// Usage - returns only your custom content
const customWorkouts = await fetchCustomWorkouts('Fitness', 10);
```

## Pagination

For large result sets, use pagination with the `lastDocId` parameter to fetch subsequent pages.

**How it works:**
1. **First request:** Omit `lastDocId` to get the first page
2. **Store the ID:** Save the `lastDocId` from the response
3. **Next request:** Pass the saved ID as `lastDocId` to get the next page
4. **Repeat:** Continue until no more results are returned

**Paginated Fetching**

_Swift (iOS)_
```swift
// Fetch all workouts with pagination
func fetchAllWorkouts() async throws -> [WorkoutModel] {
    var allWorkouts: [WorkoutModel] = []
    var lastDocId: String? = nil

    repeat {
        let result = await kinestex.fetchWorkouts(
            category: "Fitness",
            limit: 10,
            lastDocId: lastDocId
        )

        switch result {
        case .success(let response):
            allWorkouts.append(contentsOf: response.workouts)
            lastDocId = response.lastDocId

            // If lastDocId is empty or nil, we've reached the end
            if lastDocId?.isEmpty ?? true {
                lastDocId = nil
            }

            print("Fetched page with \(response.workouts.count) workouts")

        case .failure(let error):
            throw error
        }
    } while lastDocId != nil

    print("Total workouts fetched: \(allWorkouts.count)")
    return allWorkouts
}
```

_Kotlin (Android)_
```kotlin
// Fetch all workouts with pagination
suspend fun fetchAllWorkouts(): List<WorkoutModel> {
    val allWorkouts = mutableListOf<WorkoutModel>()
    var lastDocId: String? = null

    do {
        val result = KinesteXSDK.api.fetchAPIContentData(
            contentType = ContentType.WORKOUT,
            category = "Fitness",
            limit = 10,
            lastDocId = lastDocId
        )

        when (result) {
            is APIContentResult.Workouts -> {
                allWorkouts.addAll(result.workouts)
                lastDocId = result.lastDocId?.takeIf { it.isNotEmpty() }

                Log.d("API", "Fetched page with ${result.workouts.size} workouts")
            }
            is APIContentResult.Error -> {
                throw Exception(result.message)
            }
            else -> {
                lastDocId = null
            }
        }
    } while (lastDocId != null)

    Log.d("API", "Total workouts fetched: ${allWorkouts.size}")
    return allWorkouts
}
```

_Flutter_
```dart
// Fetch all workouts with pagination
Future<List<WorkoutModel>> fetchAllWorkouts() async {
  final allWorkouts = <WorkoutModel>[];
  String? lastDocId;

  do {
    final result = await KinesteXAIFramework.apiService.fetchContent(
      contentType: ContentType.workout,
      category: "Fitness",
      limit: 10,
      lastDocId: lastDocId,
    );

    switch (result) {
      case WorkoutsResult(:final response):
        allWorkouts.addAll(response.workouts);
        lastDocId = response.lastDocId.isNotEmpty ? response.lastDocId : null;

        print('Fetched page with ${response.workouts.length} workouts');

      case ErrorResult(:final message):
        throw Exception(message);

      default:
        lastDocId = null;
    }
  } while (lastDocId != null);

  print('Total workouts fetched: ${allWorkouts.length}');
  return allWorkouts;
}
```

_React Native_
```jsx
// Fetch all workouts with pagination
const fetchAllWorkouts = async (category: string): Promise<WorkoutModel[]> => {
  const allWorkouts: WorkoutModel[] = [];
  let lastDocId: string | undefined = undefined;

  do {
    const params = new URLSearchParams({
      category,
      limit: '10',
    });

    if (lastDocId) {
      params.append('lastDocId', lastDocId);
    }

    const response = await fetch(
      `${BASE_URL}/workouts?${params}`,
      { headers }
    );

    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`);
    }

    const data = await response.json();
    allWorkouts.push(...data.workouts);
    lastDocId = data.lastDocId || undefined;

    console.log(`Fetched page with ${data.workouts.length} workouts`);

  } while (lastDocId);

  console.log(`Total workouts fetched: ${allWorkouts.length}`);
  return allWorkouts;
};
```

_HTML / JavaScript_
```html
// Fetch all workouts with pagination
async function fetchAllWorkouts(category) {
  const allWorkouts = [];
  let lastDocId = null;

  do {
    const params = new URLSearchParams({
      category,
      limit: '10',
    });

    if (lastDocId) {
      params.append('lastDocId', lastDocId);
    }

    const response = await fetch(
      `${BASE_URL}/workouts?${params}`,
      { headers }
    );

    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`);
    }

    const data = await response.json();
    allWorkouts.push(...data.workouts);
    lastDocId = data.lastDocId || null;

    console.log(`Fetched page with ${data.workouts.length} workouts`);

  } while (lastDocId);

  console.log(`Total workouts fetched: ${allWorkouts.length}`);
  return allWorkouts;
}
```

_React (TypeScript)_
```tsx
// Fetch all workouts with pagination
const fetchAllWorkouts = async (category: string): Promise<WorkoutModel[]> => {
  const allWorkouts: WorkoutModel[] = [];
  let lastDocId: string | undefined = undefined;

  do {
    const params = new URLSearchParams({
      category,
      limit: '10',
    });

    if (lastDocId) {
      params.append('lastDocId', lastDocId);
    }

    const response = await fetch(
      `${BASE_URL}/workouts?${params}`,
      { headers }
    );

    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`);
    }

    const data: WorkoutsResponse = await response.json();
    allWorkouts.push(...data.workouts);
    lastDocId = data.lastDocId || undefined;

    console.log(`Fetched page with ${data.workouts.length} workouts`);

  } while (lastDocId);

  console.log(`Total workouts fetched: ${allWorkouts.length}`);
  return allWorkouts;
};
```

## Error Handling

Handle API errors gracefully in your application.

**Response Codes:**
| Status | Description |
|--------|-------------|
| 200/201 | Request successful |
| 400 | Validation error (check parameters) |
| 401 | Unauthorized (invalid API key) |
| 404 | Content not found |
| 500 | Internal server error |

**Error Handling Patterns**

_Swift (iOS)_
```swift
// Comprehensive error handling with Swift SDK
Task {
    let result = await kinestex.fetchWorkouts(category: "Fitness", limit: 10)

    switch result {
    case .success(let response):
        // Handle successful response
        let workouts = response.workouts
        print("Success: Fetched \(workouts.count) workouts")

    case .failure(let error):
        // Handle different error types
        if let urlError = error as? URLError {
            switch urlError.code {
            case .notConnectedToInternet:
                print("No internet connection")
            case .timedOut:
                print("Request timed out")
            default:
                print("Network error: \(urlError.localizedDescription)")
            }
        } else {
            print("Error: \(error.localizedDescription)")
        }
    }
}

// Using fetchContent for advanced error handling
Task {
    let result = await kinestex.fetchContent(
        contentType: .workout,
        id: "invalid_id"
    )

    switch result {
    case .workout(let workout):
        print("Found: \(workout.title)")

    case .error(let message):
        // API returned an error message
        print("API Error: \(message)")

    case .rawData(let data, let errorMessage):
        // Parsing failed, but raw data is available
        print("Parse error: \(errorMessage ?? "Unknown")")
        print("Raw data: \(data)")

    default:
        print("Unexpected result type")
    }
}
```

_Kotlin (Android)_
```kotlin
// Comprehensive error handling with Kotlin SDK
lifecycleScope.launch {
    try {
        val result = withContext(Dispatchers.IO) {
            KinesteXSDK.api.fetchAPIContentData(
                contentType = ContentType.WORKOUT,
                category = "Fitness",
                limit = 10
            )
        }

        when (result) {
            is APIContentResult.Workouts -> {
                // Handle successful response
                val workouts = result.workouts
                Log.d("API", "Success: Fetched ${workouts.size} workouts")
            }
            is APIContentResult.Error -> {
                // API returned an error
                Log.e("API", "API Error: ${result.message}")

                // Show user-friendly message
                Toast.makeText(
                    this@MainActivity,
                    "Failed to load workouts: ${result.message}",
                    Toast.LENGTH_LONG
                ).show()
            }
            else -> {
                Log.w("API", "Unexpected result type")
            }
        }
    } catch (e: Exception) {
        // Handle network or other exceptions
        Log.e("API", "Exception: ${e.message}")

        when (e) {
            is java.net.UnknownHostException -> {
                Toast.makeText(this@MainActivity, "No internet connection", Toast.LENGTH_SHORT).show()
            }
            is java.net.SocketTimeoutException -> {
                Toast.makeText(this@MainActivity, "Request timed out", Toast.LENGTH_SHORT).show()
            }
            else -> {
                Toast.makeText(this@MainActivity, "Error: ${e.message}", Toast.LENGTH_SHORT).show()
            }
        }
    }
}
```

_Flutter_
```dart
// Comprehensive error handling with Flutter SDK
// fetchContent never throws: network failures and timeouts are caught
// internally and surfaced as ErrorResult (e.g. "Network error: ...").
Future<void> fetchWithErrorHandling() async {
  final result = await KinesteXAIFramework.apiService.fetchContent(
    contentType: ContentType.workout,
    category: "Fitness",
    limit: 10,
  );

  switch (result) {
    case WorkoutsResult(:final response):
      // Handle successful response
      print('Success: Fetched ${response.workouts.length} workouts');

    case ErrorResult(:final message):
      // API error, network failure, or timeout
      print('API Error: $message');

      // Show user-friendly message
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Failed to load workouts: $message')),
      );

    case RawDataResult(:final data, :final errorMessage):
      // Parsing failed, but raw data is available
      print('Parse error: ${errorMessage ?? "Unknown"}');
      print('Raw data keys: ${data.keys}');

    default:
      print('Unexpected result type');
  }
}
```

_React Native_
```jsx
// Comprehensive error handling with fetch API
const fetchWithErrorHandling = async (): Promise<WorkoutModel[]> => {
  try {
    const response = await fetch(
      `${BASE_URL}/workouts?category=Fitness&limit=10`,
      { headers }
    );

    if (!response.ok) {
      // Handle HTTP errors
      switch (response.status) {
        case 400:
          throw new Error('Invalid request parameters');
        case 401:
          throw new Error('Invalid API key');
        case 404:
          throw new Error('Content not found');
        case 500:
          throw new Error('Server error - please try again later');
        default:
          throw new Error(`HTTP Error: ${response.status}`);
      }
    }

    const data = await response.json();

    // Check for API-level errors
    if (data.error) {
      throw new Error(data.error);
    }

    return data.workouts;

  } catch (error) {
    if (error instanceof TypeError && error.message === 'Network request failed') {
      // No internet connection
      console.error('No internet connection');
      throw new Error('Please check your internet connection');
    }

    // Re-throw the error
    throw error;
  }
};

// Usage with error handling
try {
  const workouts = await fetchWithErrorHandling();
  console.log(`Fetched ${workouts.length} workouts`);
} catch (error) {
  Alert.alert('Error', error.message);
}
```

_HTML / JavaScript_
```html
// Comprehensive error handling with fetch API
async function fetchWithErrorHandling() {
  try {
    const response = await fetch(
      `${BASE_URL}/workouts?category=Fitness&limit=10`,
      { headers }
    );

    if (!response.ok) {
      // Handle HTTP errors
      switch (response.status) {
        case 400:
          throw new Error('Invalid request parameters');
        case 401:
          throw new Error('Invalid API key');
        case 404:
          throw new Error('Content not found');
        case 500:
          throw new Error('Server error - please try again later');
        default:
          throw new Error(`HTTP Error: ${response.status}`);
      }
    }

    const data = await response.json();

    // Check for API-level errors
    if (data.error) {
      throw new Error(data.error);
    }

    return data.workouts;

  } catch (error) {
    if (error instanceof TypeError && error.message === 'Failed to fetch') {
      // No internet connection or CORS error
      console.error('Network error');
      throw new Error('Please check your internet connection');
    }

    // Re-throw the error
    throw error;
  }
}

// Usage with error handling
fetchWithErrorHandling()
  .then(workouts => console.log(`Fetched ${workouts.length} workouts`))
  .catch(error => alert(`Error: ${error.message}`));
```

_React (TypeScript)_
```tsx
// Comprehensive error handling with TypeScript
class APIError extends Error {
  constructor(
    message: string,
    public statusCode?: number,
    public originalError?: unknown
  ) {
    super(message);
    this.name = 'APIError';
  }
}

const fetchWithErrorHandling = async (): Promise<WorkoutModel[]> => {
  try {
    const response = await fetch(
      `${BASE_URL}/workouts?category=Fitness&limit=10`,
      { headers }
    );

    if (!response.ok) {
      // Handle HTTP errors
      const errorMessages: Record<number, string> = {
        400: 'Invalid request parameters',
        401: 'Invalid API key',
        404: 'Content not found',
        500: 'Server error - please try again later',
      };

      throw new APIError(
        errorMessages[response.status] || `HTTP Error: ${response.status}`,
        response.status
      );
    }

    const data = await response.json();

    // Check for API-level errors
    if (data.error) {
      throw new APIError(data.error);
    }

    return data.workouts;

  } catch (error) {
    if (error instanceof APIError) {
      throw error;
    }

    if (error instanceof TypeError) {
      throw new APIError('Please check your internet connection', undefined, error);
    }

    throw new APIError('An unexpected error occurred', undefined, error);
  }
};

// Usage with error handling
try {
  const workouts = await fetchWithErrorHandling();
  console.log(`Fetched ${workouts.length} workouts`);
} catch (error) {
  if (error instanceof APIError) {
    console.error(`API Error (${error.statusCode}): ${error.message}`);
  }
}
```

## Data Models

Reference for the data structures returned by the Content API.

**WorkoutModel:**
| Field | Type | Description |
|-------|------|-------------|
| id | String | Unique identifier |
| title | String | Workout name |
| category | String | Fitness or Rehabilitation |
| calories | Int? | Estimated calories burned |
| totalMinutes | Int? | Total duration in minutes |
| bodyParts | [String] | Targeted body parts |
| difficultyLevel | String? | Difficulty level |
| description | String | Workout description |
| imgURL | String | Workout thumbnail image |
| sequence | [ExerciseModel] | List of exercises |

**ExerciseModel:**
| Field | Type | Description |
|-------|------|-------------|
| id | String | Unique identifier |
| title | String | Exercise name |
| bodyParts | [String] | Targeted body parts |
| videoURL | String | Demo video URL |
| thumbnailURL | String | Thumbnail image URL |
| modelId | String | Motion tracking model ID (use in Camera Component) |
| description | String | Exercise description |
| steps | [String] | Step-by-step instructions |
| commonMistakes | String | Common mistakes to avoid |
| tips | String | Tips for proper form |

**PlanModel:**
| Field | Type | Description |
|-------|------|-------------|
| id | String | Unique identifier |
| title | String | Plan name |
| imgURL | String | Plan thumbnail image |
| category | PlanModelCategory | Category with description and levels |
| levels | [String: PlanLevel] | Dictionary of levels (1, 2, 3, etc.) |
| createdBy | String | Creator identifier |

**PlanLevel:**
| Field | Type | Description |
|-------|------|-------------|
| title | String | Level title |
| description | String | Level description |
| days | [String: PlanDay] | Dictionary of days |

**PlanDay:**
| Field | Type | Description |
|-------|------|-------------|
| title | String | Day title |
| description | String | Day description |
| workouts | [WorkoutSummary]? | List of workouts for this day |

**Working with Models**

_Swift (iOS)_
```swift
// Accessing workout model properties
Task {
    let result = await kinestex.fetchWorkout(id: "9zE1kzOzpU5d5dAJrPOY")

    switch result {
    case .success(let workout):
        // Basic properties
        print("Title: \(workout.title)")
        print("Category: \(workout.category ?? "N/A")")
        print("Duration: \(workout.totalMinutes ?? 0) minutes")
        print("Calories: \(workout.totalCalories ?? 0)")
        print("Difficulty: \(workout.difficultyLevel ?? "N/A")")

        // Body parts
        print("Targets: \(workout.bodyParts.joined(separator: ", "))")

        // Exercise sequence
        print("\nExercises (\(workout.sequence.count)):")
        for (index, exercise) in workout.sequence.enumerated() {
            print("\(index + 1). \(exercise.title)")
            print("   Model ID: \(exercise.modelId)")  // Use for Camera Component
            print("   Reps: \(exercise.workoutReps ?? exercise.averageReps ?? 0)")
        }

        // Access raw JSON if needed
        if let rawJSON = workout.rawJSON {
            print("\nRaw JSON available: \(rawJSON.keys.count) keys")
        }

    case .failure(let error):
        print("Error: \(error.localizedDescription)")
    }
}

// Working with plan structure
Task {
    let result = await kinestex.fetchPlan(id: "22B3qRU2r75hVXHgGiGx")

    switch result {
    case .success(let plan):
        print("Plan: \(plan.title)")
        print("Category: \(plan.category.description)")

        // Iterate through levels
        for (levelKey, level) in plan.levels {
            print("\nLevel \(levelKey): \(level.title)")

            // Iterate through days
            for (dayKey, day) in level.days {
                print("  Day \(dayKey): \(day.title)")

                // List workouts for this day
                if let workouts = day.workouts {
                    for workout in workouts {
                        print("    - \(workout.title) (\(workout.totalMinutes) min)")
                    }
                }
            }
        }

    case .failure(let error):
        print("Error: \(error.localizedDescription)")
    }
}
```

_Kotlin (Android)_
```kotlin
// Accessing workout model properties
lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) {
        KinesteXSDK.api.fetchAPIContentData(
            contentType = ContentType.WORKOUT,
            id = "9zE1kzOzpU5d5dAJrPOY"
        )
    }

    when (result) {
        is APIContentResult.Workout -> {
            val workout = result.workout

            // Basic properties
            Log.d("API", "Title: ${workout.title}")
            Log.d("API", "Category: ${workout.category}")
            Log.d("API", "Duration: ${workout.totalMinutes} minutes")
            Log.d("API", "Calories: ${workout.calories}")

            // Body parts
            Log.d("API", "Targets: ${workout.bodyParts.joinToString(", ")}")

            // Exercise sequence
            Log.d("API", "Exercises (${workout.sequence.size}):")
            workout.sequence.forEachIndexed { index, exercise ->
                Log.d("API", "${index + 1}. ${exercise.title}")
                Log.d("API", "   Model ID: ${exercise.modelId}")  // Use for Camera Component
            }

            // Pretty print as JSON
            val gson = GsonBuilder().setPrettyPrinting().create()
            val prettyJson = gson.toJson(workout)
            Log.d("API", "JSON:\n$prettyJson")
        }
        is APIContentResult.Error -> {
            Log.e("API", "Error: ${result.message}")
        }
        else -> {}
    }
}
```

_Flutter_
```dart
// Accessing workout model properties
Future<void> workWithModels() async {
  final result = await KinesteXAIFramework.apiService.fetchContent(
    contentType: ContentType.workout,
    id: "9zE1kzOzpU5d5dAJrPOY",
  );

  switch (result) {
    case WorkoutResult(:final workout):
      // Basic properties
      print('Title: ${workout.title}');
      print('Category: ${workout.category}');
      print('Duration: ${workout.totalMinutes} minutes');
      print('Calories: ${workout.totalCalories}');
      print('Difficulty: ${workout.difficultyLevel}');

      // Body parts
      print('Targets: ${workout.bodyParts.join(", ")}');

      // Exercise sequence
      print('\nExercises (${workout.sequence.length}):');
      for (var i = 0; i < workout.sequence.length; i++) {
        final exercise = workout.sequence[i];
        print('${i + 1}. ${exercise.title}');
        print('   Model ID: ${exercise.modelId}');  // Use for Camera Component
      }

      // Access raw JSON if needed
      if (workout.rawJSON != null) {
        print('\nRaw JSON available: ${workout.rawJSON!.keys.length} keys');
      }

    case ErrorResult(:final message):
      print('Error: $message');

    default:
      break;
  }
}

// Working with plan structure
Future<void> workWithPlan() async {
  final result = await KinesteXAIFramework.apiService.fetchContent(
    contentType: ContentType.plan,
    id: "22B3qRU2r75hVXHgGiGx",
  );

  switch (result) {
    case PlanResult(:final plan):
      print('Plan: ${plan.title}');
      print('Category: ${plan.category.description}');

      // Iterate through levels
      plan.levels.forEach((levelKey, level) {
        print('\nLevel $levelKey: ${level.title}');

        // Iterate through days
        level.days.forEach((dayKey, day) {
          print('  Day $dayKey: ${day.title}');

          // List workouts for this day
          day.workouts?.forEach((workout) {
            print('    - ${workout.title} (${workout.totalMinutes} min)');
          });
        });
      });

    case ErrorResult(:final message):
      print('Error: $message');

    default:
      break;
  }
}
```

_React Native_
```jsx
// TypeScript interfaces for Content API models
interface WorkoutModel {
  id: string;
  title: string;
  category: string;
  calories: number;
  total_minutes: number;
  body_parts: string[];
  dif_level: string;
  description: string;
  workout_desc_img: string;
  sequence: ExerciseModel[];
}

interface ExerciseModel {
  id: string;
  title: string;
  body_parts: string[];
  video_url: string;
  male_video_url: string;
  thumbnail_url: string;
  male_thumbnail_url: string;
  model_id: string;
  description: string;
  steps: string[];
  common_mistakes: string;
  tips: string;
  workout_reps?: number;
  workout_countdown?: number;
  average_reps?: number;
  average_countdown?: number;
  rest_duration?: number;
}

interface PlanModel {
  id: string;
  title: string;
  img_url: string;
  category: {
    description: string;
    levels: Record<string, number>;
  };
  levels: Record<string, PlanLevel>;
  created_by: string;
}

interface PlanLevel {
  title: string;
  description: string;
  days: Record<string, PlanDay>;
}

interface PlanDay {
  title: string;
  description: string;
  workouts?: WorkoutSummary[];
}

interface WorkoutSummary {
  id: string;
  img_url: string;
  title: string;
  calories?: number;
  total_minutes: number;
}

// Working with fetched data
const displayWorkout = (workout: WorkoutModel) => {
  console.log(`Title: ${workout.title}`);
  console.log(`Duration: ${workout.total_minutes} minutes`);
  console.log(`Calories: ${workout.calories}`);
  console.log(`Targets: ${workout.body_parts.join(', ')}`);

  console.log(`\nExercises (${workout.sequence.length}):`);
  workout.sequence.forEach((exercise, index) => {
    console.log(`${index + 1}. ${exercise.title}`);
    console.log(`   Model ID: ${exercise.model_id}`);  // Use for Camera Component
  });
};
```

_HTML / JavaScript_
```html
// Working with fetched workout data
function displayWorkout(workout) {
  console.log(`Title: ${workout.title}`);
  console.log(`Duration: ${workout.total_minutes} minutes`);
  console.log(`Calories: ${workout.calories}`);
  console.log(`Targets: ${workout.body_parts.join(', ')}`);

  console.log(`\nExercises (${workout.sequence.length}):`);
  workout.sequence.forEach((exercise, index) => {
    console.log(`${index + 1}. ${exercise.title}`);
    console.log(`   Model ID: ${exercise.model_id}`);  // Use for Camera Component
  });
}

// Working with plan structure
function displayPlan(plan) {
  console.log(`Plan: ${plan.title}`);
  console.log(`Category: ${plan.category.description}`);

  // Iterate through levels
  Object.entries(plan.levels).forEach(([levelKey, level]) => {
    console.log(`\nLevel ${levelKey}: ${level.title}`);

    // Iterate through days
    Object.entries(level.days).forEach(([dayKey, day]) => {
      console.log(`  Day ${dayKey}: ${day.title}`);

      // List workouts for this day
      if (day.workouts) {
        day.workouts.forEach(workout => {
          console.log(`    - ${workout.title} (${workout.total_minutes} min)`);
        });
      }
    });
  });
}
```

_React (TypeScript)_
```tsx
// Full TypeScript interfaces for Content API models
interface WorkoutModel {
  id: string;
  title: string;
  category: string;
  calories: number;
  total_minutes: number;
  body_parts: string[];
  dif_level: string;
  description: string;
  workout_desc_img: string;
  sequence: ExerciseModel[];
}

interface ExerciseModel {
  id: string;
  title: string;
  body_parts: string[];
  video_url: string;
  male_video_url: string;
  thumbnail_url: string;
  male_thumbnail_url: string;
  model_id: string;
  description: string;
  steps: string[];
  common_mistakes: string;
  tips: string;
  workout_reps?: number;
  workout_countdown?: number;
  average_reps?: number;
  average_countdown?: number;
  rest_duration?: number;
}

interface PlanModel {
  id: string;
  title: string;
  img_url: string;
  category: PlanCategory;
  levels: Record<string, PlanLevel>;
  created_by: string;
}

interface PlanCategory {
  description: string;
  levels: Record<string, number>;
}

interface PlanLevel {
  title: string;
  description: string;
  days: Record<string, PlanDay>;
}

interface PlanDay {
  title: string;
  description: string;
  workouts?: WorkoutSummary[];
}

interface WorkoutSummary {
  id: string;
  img_url: string;
  title: string;
  calories?: number;
  total_minutes: number;
}

// Helper function to display workout
const displayWorkout = (workout: WorkoutModel): void => {
  console.log(`Title: ${workout.title}`);
  console.log(`Duration: ${workout.total_minutes} minutes`);
  console.log(`Calories: ${workout.calories}`);
  console.log(`Targets: ${workout.body_parts.join(', ')}`);

  console.log(`\nExercises (${workout.sequence.length}):`);
  workout.sequence.forEach((exercise, index) => {
    console.log(`${index + 1}. ${exercise.title}`);
    console.log(`   Model ID: ${exercise.model_id}`);  // Use for Camera Component
  });
};
```

---
Source: https://www.kinestex.com/docs/content-api · Index: https://www.kinestex.com/llms.txt
