> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tktchurch.com/llms.txt
> Use this file to discover all available pages before exploring further.

# List Livestreams

> List all livestreams with optional filtering

### Query Parameters

<ParamField query="status" type="string" required={false}>
  Filter by livestream status. One of:

  * `scheduled`: Upcoming livestream
  * `live`: Currently streaming
  * `ended`: Completed livestream
  * `cancelled`: Cancelled livestream
</ParamField>

<ParamField query="tag" type="string" required={false}>
  Filter by tag
</ParamField>

<ParamField query="start" type="string" required={false}>
  Filter by start date (ISO 8601 format)
</ParamField>

<ParamField query="end" type="string" required={false}>
  Filter by end date (ISO 8601 format)
</ParamField>

<ParamField query="page" type="integer" required={false}>
  Page number for pagination (default: 1)
</ParamField>

<ParamField query="per" type="integer" required={false}>
  Items per page (default: 10)
</ParamField>

### Response

<ResponseField name="items" type="array">
  Array of livestream objects

  <Expandable title="Livestream Object">
    <ResponseField name="id" type="string">
      Livestream's unique identifier (UUID)
    </ResponseField>

    <ResponseField name="title" type="string">
      Title of the livestream
    </ResponseField>

    <ResponseField name="description" type="string">
      Description of the livestream
    </ResponseField>

    <ResponseField name="youtubeUrl" type="string" required={false}>
      YouTube URL for the livestream
    </ResponseField>

    <ResponseField name="customStreamUrl" type="string" required={false}>
      Custom streaming URL
    </ResponseField>

    <ResponseField name="status" type="string">
      Current status of the livestream (scheduled, live, ended, or cancelled)
    </ResponseField>

    <ResponseField name="scheduledStartTime" type="string" required={false}>
      Scheduled start time in ISO 8601 format
    </ResponseField>

    <ResponseField name="actualStartTime" type="string" required={false}>
      Actual start time in ISO 8601 format
    </ResponseField>

    <ResponseField name="endTime" type="string" required={false}>
      End time in ISO 8601 format
    </ResponseField>

    <ResponseField name="tags" type="array">
      Array of tags associated with the livestream
    </ResponseField>

    <ResponseField name="thumbnailUrl" type="string" required={false}>
      URL of the livestream thumbnail
    </ResponseField>

    <ResponseField name="thumbnail" type="object" required={false}>
      Thumbnail file information

      <Expandable title="Thumbnail Object">
        <ResponseField name="id" type="string">
          File's unique identifier (UUID)
        </ResponseField>

        <ResponseField name="url" type="string">
          URL to access the file
        </ResponseField>

        <ResponseField name="provider" type="string">
          Storage provider (s3 or local)
        </ResponseField>

        <ResponseField name="key" type="string">
          Storage key/path of the file
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="createdByUserId" type="string">
      UUID of the user who created the livestream
    </ResponseField>

    <ResponseField name="updatedByUserId" type="string">
      UUID of the user who last updated the livestream
    </ResponseField>

    <ResponseField name="createdAt" type="string">
      Creation timestamp in ISO 8601 format
    </ResponseField>

    <ResponseField name="updatedAt" type="string">
      Last update timestamp in ISO 8601 format
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="metadata" type="object">
  Pagination metadata

  <Expandable title="Metadata Object">
    <ResponseField name="page" type="integer">
      Current page number
    </ResponseField>

    <ResponseField name="per" type="integer">
      Items per page
    </ResponseField>

    <ResponseField name="total" type="integer">
      Total number of items
    </ResponseField>

    <ResponseField name="pageCount" type="integer">
      Total number of pages
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X GET "https://api.tktchurch.com/v1/livestreams?status=live&tag=sunday-service&start=2024-01-01T00:00:00Z"
  ```

  ```javascript JavaScript theme={null}
  const listLivestreams = async (params = {}) => {
    const queryString = new URLSearchParams(params).toString();
    const response = await fetch(
      `https://api.tktchurch.com/v1/livestreams?${queryString}`
    );

    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.reason || 'Failed to list livestreams');
    }

    return response.json();
  };

  // Usage
  try {
    const livestreams = await listLivestreams({
      status: 'live',
      tag: 'sunday-service',
      start: '2024-01-01T00:00:00Z'
    });
    console.log('Livestreams:', livestreams);
  } catch (error) {
    console.error('Error:', error.message);
  }
  ```

  ```swift Swift theme={null}
  struct Livestream: Codable {
      let id: UUID
      let title: String
      let description: String
      let youtubeUrl: String?
      let customStreamUrl: String?
      let status: String
      let scheduledStartTime: Date?
      let actualStartTime: Date?
      let endTime: Date?
      let tags: [String]
      let thumbnailUrl: String?
      let thumbnail: ThumbnailInfo?
      let createdByUserId: UUID
      let updatedByUserId: UUID
      let createdAt: Date?
      let updatedAt: Date?
      
      struct ThumbnailInfo: Codable {
          let id: UUID?
          let url: String
          let provider: String
          let key: String
      }
  }

  struct PageResponse<T: Codable>: Codable {
      let items: [T]
      let metadata: PageMetadata
      
      struct PageMetadata: Codable {
          let page: Int
          let per: Int
          let total: Int
          let pageCount: Int
      }
  }

  func listLivestreams(
      status: String? = nil,
      tag: String? = nil,
      start: Date? = nil
  ) async throws -> PageResponse<Livestream> {
      var components = URLComponents(string: "https://api.tktchurch.com/v1/livestreams")!
      var queryItems: [URLQueryItem] = []
      
      if let status = status {
          queryItems.append(URLQueryItem(name: "status", value: status))
      }
      if let tag = tag {
          queryItems.append(URLQueryItem(name: "tag", value: tag))
      }
      if let start = start {
          let formatter = ISO8601DateFormatter()
          queryItems.append(URLQueryItem(name: "start", value: formatter.string(from: start)))
      }
      
      components.queryItems = queryItems
      
      let (data, _) = try await URLSession.shared.data(from: components.url!)
      return try JSONDecoder().decode(PageResponse<Livestream>.self, from: data)
  }

  // Usage
  do {
      let livestreams = try await listLivestreams(
          status: "live",
          tag: "sunday-service",
          start: Date()
      )
      print("Livestreams:", livestreams)
  } catch {
      print("Error:", error)
  }
  ```

  ```kotlin Kotlin theme={null}
  data class Livestream(
      val id: UUID,
      val title: String,
      val description: String,
      val youtubeUrl: String?,
      val customStreamUrl: String?,
      val status: String,
      val scheduledStartTime: String?,
      val actualStartTime: String?,
      val endTime: String?,
      val tags: List<String>,
      val thumbnailUrl: String?,
      val thumbnail: ThumbnailInfo?,
      val createdByUserId: UUID,
      val updatedByUserId: UUID,
      val createdAt: String?,
      val updatedAt: String?
  ) {
      data class ThumbnailInfo(
          val id: UUID?,
          val url: String,
          val provider: String,
          val key: String
      )
  }

  data class PageResponse<T>(
      val items: List<T>,
      val metadata: PageMetadata
  ) {
      data class PageMetadata(
          val page: Int,
          val per: Int,
          val total: Int,
          val pageCount: Int
      )
  }

  suspend fun listLivestreams(
      status: String? = null,
      tag: String? = null,
      start: String? = null
  ): PageResponse<Livestream> {
      val url = buildString {
          append("https://api.tktchurch.com/v1/livestreams")
          val params = listOfNotNull(
              status?.let { "status=$it" },
              tag?.let { "tag=$it" },
              start?.let { "start=$it" }
          )
          if (params.isNotEmpty()) {
              append("?${params.joinToString("&")}")
          }
      }

      return withContext(Dispatchers.IO) {
          val request = Request.Builder()
              .url(url)
              .get()
              .build()

          client.newCall(request).execute().use { response ->
              if (!response.isSuccessful) {
                  throw IOException("Unexpected response ${response.code}")
              }
              
              val body = response.body?.string() ?: throw IOException("Empty response")
              Json.decodeFromString<PageResponse<Livestream>>(body)
          }
      }
  }

  // Usage
  try {
      val livestreams = listLivestreams(
          status = "live",
          tag = "sunday-service",
          start = "2024-01-01T00:00:00Z"
      )
      println("Livestreams: $livestreams")
  } catch (e: Exception) {
      println("Error: ${e.message}")
  }
  ```

  ```typescript React Native theme={null}
  interface Thumbnail {
    id?: string;
    url: string;
    provider: 's3' | 'local';
    key: string;
  }

  interface Livestream {
    id: string;
    title: string;
    description: string;
    youtubeUrl?: string;
    customStreamUrl?: string;
    status: 'scheduled' | 'live' | 'ended' | 'cancelled';
    scheduledStartTime?: string;
    actualStartTime?: string;
    endTime?: string;
    tags: string[];
    thumbnailUrl?: string;
    thumbnail?: ThumbnailInfo?
    createdByUserId: string;
    updatedByUserId: string;
    createdAt?: string;
    updatedAt?: string;
  }

  interface PageMetadata {
    page: number;
    per: number;
    total: number;
    pageCount: number;
  }

  interface PageResponse<T> {
    items: T[];
    metadata: PageMetadata;
  }

  interface ListLivestreamsParams {
    status?: string;
    tag?: string;
    start?: string;
    page?: number;
    per?: number;
  }

  const listLivestreams = async (params: ListLivestreamsParams = {}): Promise<PageResponse<Livestream>> => {
    const queryString = new URLSearchParams(
      Object.entries(params).filter(([_, value]) => value != null) as [string, string][]
    ).toString();

    try {
      const response = await axios.get<PageResponse<Livestream>>(
        `https://api.tktchurch.com/v1/livestreams${queryString ? `?${queryString}` : ''}`
      );
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error)) {
        throw new Error(error.response?.data?.reason || 'Failed to list livestreams');
      }
      throw error;
    }
  };

  // Usage
  try {
    const livestreams = await listLivestreams({
      status: 'live',
      tag: 'sunday-service',
      start: '2024-01-01T00:00:00Z'
    });
    console.log('Livestreams:', livestreams);
  } catch (error) {
    console.error('Error:', error.message);
  }
  ```
</RequestExample>

<ResponseExample>
  ```json 200 Success theme={null}
  {
    "items": [
      {
        "id": "123e4567-e89b-12d3-a456-426614174000",
        "title": "Sunday Service",
        "description": "Join us for our weekly Sunday service",
        "youtubeUrl": "https://youtube.com/watch?v=abc123",
        "customStreamUrl": null,
        "status": "live",
        "scheduledStartTime": "2024-01-21T10:00:00Z",
        "actualStartTime": "2024-01-21T10:02:00Z",
        "endTime": null,
        "tags": ["sunday-service", "worship"],
        "thumbnailUrl": "https://example.com/thumbnail.jpg",
        "thumbnail": {
          "id": "123e4567-e89b-12d3-a456-426614174001",
          "url": "https://storage.example.com/thumbnails/abc123.jpg",
          "provider": "s3",
          "key": "thumbnails/abc123.jpg"
        },
        "createdByUserId": "123e4567-e89b-12d3-a456-426614174002",
        "updatedByUserId": "123e4567-e89b-12d3-a456-426614174002",
        "createdAt": "2024-01-20T15:00:00Z",
        "updatedAt": "2024-01-21T10:02:00Z"
      }
    ],
    "metadata": {
      "page": 1,
      "per": 10,
      "total": 1,
      "pageCount": 1
    }
  }
  ```
</ResponseExample>
