> ## 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.

# Update Livestream

> Update an existing livestream

<Note>
  This endpoint requires authentication and the `updateLivestream` permission.
</Note>

### Path Parameters

<ParamField path="id" type="string" required>
  The UUID of the livestream to update
</ParamField>

### Request Body

<ParamField body="title" type="string" required={false}>
  Title of the livestream
</ParamField>

<ParamField body="description" type="string" required={false}>
  Description of the livestream
</ParamField>

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

<ParamField body="customStreamUrl" type="string" required={false}>
  Custom streaming URL
</ParamField>

<ParamField body="status" type="string" required={false}>
  Current status of the livestream. One of:

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

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

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

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

<ParamField body="tags" type="array" required={false}>
  Array of tags associated with the livestream
</ParamField>

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

<ParamField body="thumbnailId" type="string" required={false}>
  UUID of the uploaded thumbnail file
</ParamField>

### Response

Returns the updated 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
</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>

### Error Responses

<ResponseField name="error" type="object">
  Error details when the request fails

  <Expandable title="Error Object">
    <ResponseField name="status" type="integer">
      HTTP status code
    </ResponseField>

    <ResponseField name="reason" type="string">
      Error message explaining why the request failed
    </ResponseField>
  </Expandable>
</ResponseField>

<Note>
  Common error cases:

  * 400 Bad Request: Invalid request body
  * 401 Unauthorized: Missing or invalid access token
  * 403 Forbidden: Missing required permission
  * 404 Not Found: Livestream not found
</Note>

<RequestExample>
  ```bash cURL theme={null}
  curl -X PUT "https://api.tktchurch.com/v1/livestreams/123e4567-e89b-12d3-a456-426614174000" \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
    -H "Content-Type: application/json" \
    -d '{
      "status": "live",
      "actualStartTime": "2024-01-21T10:02:00Z",
      "tags": ["sunday-service", "worship", "live"]
    }'
  ```

  ```javascript JavaScript theme={null}
  const updateLivestream = async (accessToken, id, updates) => {
    const response = await fetch(
      `https://api.tktchurch.com/v1/livestreams/${id}`,
      {
        method: 'PUT',
        headers: {
          'Authorization': `Bearer ${accessToken}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(updates)
      }
    );

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

    return response.json();
  };

  // Usage
  try {
    const livestream = await updateLivestream(
      'eyJhbGciOiJIUzI1NiIs...',
      '123e4567-e89b-12d3-a456-426614174000',
      {
        status: 'live',
        actualStartTime: '2024-01-21T10:02:00Z',
        tags: ['sunday-service', 'worship', 'live']
      }
    );
    console.log('Updated livestream:', livestream);
  } catch (error) {
    console.error('Error:', error.message);
  }
  ```

  ```swift Swift theme={null}
  struct UpdateLivestreamRequest: Codable {
      let title: String?
      let description: String?
      let youtubeUrl: String?
      let customStreamUrl: String?
      let status: String?
      let scheduledStartTime: String?
      let actualStartTime: String?
      let endTime: String?
      let tags: [String]?
      let thumbnailUrl: String?
      let thumbnailId: UUID?
  }

  func updateLivestream(
      accessToken: String,
      id: UUID,
      request: UpdateLivestreamRequest
  ) async throws -> Livestream {
      var urlRequest = URLRequest(url: URL(string: "https://api.tktchurch.com/v1/livestreams/\(id)")!)
      urlRequest.httpMethod = "PUT"
      urlRequest.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
      urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
      
      urlRequest.httpBody = try JSONEncoder().encode(request)
      
      let (data, response) = try await URLSession.shared.data(for: urlRequest)
      
      guard let httpResponse = response as? HTTPURLResponse else {
          throw URLError(.badServerResponse)
      }
      
      if httpResponse.statusCode == 404 {
          throw URLError(.resourceNotFound)
      }
      
      if httpResponse.statusCode != 200 {
          throw URLError(.badServerResponse)
      }
      
      return try JSONDecoder().decode(Livestream.self, from: data)
  }

  // Usage
  do {
      let request = UpdateLivestreamRequest(
          title: nil,
          description: nil,
          youtubeUrl: nil,
          customStreamUrl: nil,
          status: "live",
          scheduledStartTime: nil,
          actualStartTime: "2024-01-21T10:02:00Z",
          endTime: nil,
          tags: ["sunday-service", "worship", "live"],
          thumbnailUrl: nil,
          thumbnailId: nil
      )
      
      let livestream = try await updateLivestream(
          accessToken: "eyJhbGciOiJIUzI1NiIs...",
          id: UUID(uuidString: "123e4567-e89b-12d3-a456-426614174000")!,
          request: request
      )
      print("Updated livestream:", livestream)
  } catch {
      print("Error:", error)
  }
  ```

  ```kotlin Kotlin theme={null}
  data class UpdateLivestreamRequest(
      val title: String? = null,
      val description: String? = null,
      val youtubeUrl: String? = null,
      val customStreamUrl: String? = null,
      val status: String? = null,
      val scheduledStartTime: String? = null,
      val actualStartTime: String? = null,
      val endTime: String? = null,
      val tags: List<String>? = null,
      val thumbnailUrl: String? = null,
      val thumbnailId: UUID? = null
  )

  suspend fun updateLivestream(
      accessToken: String,
      id: UUID,
      request: UpdateLivestreamRequest
  ): Livestream {
      val requestBody = Json.encodeToString(request)

      val httpRequest = Request.Builder()
          .url("https://api.tktchurch.com/v1/livestreams/$id")
          .put(RequestBody.create(MediaType.parse("application/json"), requestBody))
          .header("Authorization", "Bearer $accessToken")
          .build()

      return withContext(Dispatchers.IO) {
          client.newCall(httpRequest).execute().use { response ->
              if (!response.isSuccessful) {
                  throw when (response.code) {
                      404 -> NoSuchElementException("Livestream not found")
                      else -> IOException("Unexpected response ${response.code}")
                  }
              }
              
              val body = response.body?.string() ?: throw IOException("Empty response")
              Json.decodeFromString<Livestream>(body)
          }
      }
  }

  // Usage
  try {
      val request = UpdateLivestreamRequest(
          status = "live",
          actualStartTime = "2024-01-21T10:02:00Z",
          tags = listOf("sunday-service", "worship", "live")
      )
      
      val livestream = updateLivestream(
          "eyJhbGciOiJIUzI1NiIs...",
          UUID.fromString("123e4567-e89b-12d3-a456-426614174000"),
          request
      )
      println("Updated livestream: $livestream")
  } catch (e: Exception) {
      println("Error: ${e.message}")
  }
  ```

  ```typescript React Native theme={null}
  interface UpdateLivestreamRequest {
    title?: string;
    description?: string;
    youtubeUrl?: string;
    customStreamUrl?: string;
    status?: 'scheduled' | 'live' | 'ended' | 'cancelled';
    scheduledStartTime?: string;
    actualStartTime?: string;
    endTime?: string;
    tags?: string[];
    thumbnailUrl?: string;
    thumbnailId?: string;
  }

  const updateLivestream = async (
    accessToken: string,
    id: string,
    request: UpdateLivestreamRequest
  ): Promise<Livestream> => {
    try {
      const response = await axios.put<Livestream>(
        `https://api.tktchurch.com/v1/livestreams/${id}`,
        request,
        {
          headers: {
            'Authorization': `Bearer ${accessToken}`
          },
        }
      );
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error)) {
        if (error.response?.status === 404) {
          throw new Error('Livestream not found');
        }
        throw new Error(error.response?.data?.reason || 'Failed to update livestream');
      }
      throw error;
    }
  };

  // Usage
  try {
    const livestream = await updateLivestream(
      'eyJhbGciOiJIUzI1NiIs...',
      '123e4567-e89b-12d3-a456-426614174000',
      {
        status: 'live',
        actualStartTime: '2024-01-21T10:02:00Z',
        tags: ['sunday-service', 'worship', 'live']
      }
    );
    console.log('Updated livestream:', livestream);
  } catch (error) {
    console.error('Error:', error.message);
  }
  ```
</RequestExample>

<ResponseExample>
  ```json 200 Success theme={null}
  {
    "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", "live"],
    "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"
  }
  ```

  ```json 400 Bad Request theme={null}
  {
    "error": {
      "status": 400,
      "reason": "Invalid status value"
    }
  }
  ```

  ```json 401 Unauthorized theme={null}
  {
    "error": {
      "status": 401,
      "reason": "Invalid or expired access token"
    }
  }
  ```

  ```json 403 Forbidden theme={null}
  {
    "error": {
      "status": 403,
      "reason": "Missing required permission: updateLivestream"
    }
  }
  ```

  ```json 404 Not Found theme={null}
  {
    "error": {
      "status": 404,
      "reason": "Livestream not found"
    }
  }
  ```
</ResponseExample>
