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

# Co-Host Management

> Invite, observe, and manage room co-hosts with current SDK room and invitation APIs.

Co-host management is built on room invitations, room participant events, and room participant mutations. Use these APIs when a room host invites another user to broadcast, when an invited user accepts or rejects the invitation, and when the host manages a co-host during the room.

<Note>
  This page covers SDK co-host control APIs. LiveKit connection, camera and microphone publishing, and broadcaster UI are app-owned concerns after the SDK returns broadcaster data.
</Note>

## Platform Surface

| Platform   | Invite                                                | Respond                                                                                                                      | Events                                                                                                                                              | Participant control                                                                       |
| ---------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| TypeScript | `room.createInvitation(userId)`                       | `room.getInvitations()`, `invitation.accept()`, `invitation.reject()`, `InvitationRepository.cancelInvitation(invitationId)` | `InvitationRepository.getInvitations(...)`, `RoomRepository.onRoomParticipantJoined(...)`, `onRoomParticipantRemoved(...)`, and related room events | `RoomRepository.updateCohostPermission(...)`, `removeParticipant(...)`, `leaveRoom(...)`  |
| iOS        | `AmityRoom.createInvitation(_:)`                      | `room.getInvitation()`, `invitation.accept()`, `invitation.reject()`, `room.cancelInvitation(_:)`                            | `AmityRoomRepository().getCoHostEvent(roomId:)`                                                                                                     | `updateCohostPermissions(...)`, `removeParticipant(withId:userId:)`, `leaveRoom(withId:)` |
| Android    | `AmityRoom.createInvitation(userId)`                  | `room.getInvitation()`, `invitation.accept()`, `invitation.reject()`, `invitation.cancel()`                                  | `AmityVideoClient.newRoomRepository().getCoHostEvent(roomId)`                                                                                       | `updateCohostPermission(...)`, `removeRoomParticipant(...)`, `leaveRoom(...)`             |
| Flutter    | No current public room repository found in this audit | Not available                                                                                                                | Not available                                                                                                                                       | Not available                                                                             |

## Parameters

| Concept                                | TypeScript                                            | iOS                                   | Android                                 |
| -------------------------------------- | ----------------------------------------------------- | ------------------------------------- | --------------------------------------- |
| Invite one user                        | `room.createInvitation(userId)`                       | `room.createInvitation(userId)`       | `room.createInvitation(userId)`         |
| Current user's pending room invitation | `room.getInvitations()`                               | `room.getInvitation()`                | `room.getInvitation()`                  |
| Accept                                 | `invitation.accept()`                                 | `invitation.accept()`                 | `invitation.accept()`                   |
| Reject                                 | `invitation.reject()`                                 | `invitation.reject()`                 | `invitation.reject()`                   |
| Cancel                                 | `InvitationRepository.cancelInvitation(invitationId)` | `room.cancelInvitation(invitationId)` | `invitation.cancel()`                   |
| Invitation type value                  | `livestreamCohostInvite`                              | `.livestreamCoHostInvite`             | `AmityInvitationType.LIVESTREAM_COHOST` |
| Pending status                         | `"pending"`                                           | `.pending`                            | `AmityInvitationStatus.PENDING`         |

### Event and Participant Control

| Concept                | TypeScript                                                                        | iOS                                                                                                                   | Android                                                                                                                                 |
| ---------------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| Room invitation events | `InvitationRepository.getInvitations({ targetId, targetType: "room" }, callback)` | `AmityInvitationRepository().getInvitations(targetId:targetType:)` or `AmityRoomRepository().getCoHostEvent(roomId:)` | `AmityCoreClient.newInvitationRepository().getInvitations(targetId, AmityInvitation.TargetType.ROOM.value)` or `getCoHostEvent(roomId)` |
| Co-host joined         | `RoomRepository.onRoomParticipantJoined(callback)`                                | `AmityCoHostEventType.coHostJoined`                                                                                   | `AmityCoHostEvent.CoHostJoined`                                                                                                         |
| Co-host left           | `RoomRepository.onRoomParticipantLeft(callback)`                                  | `AmityCoHostEventType.coHostLeft`                                                                                     | `AmityCoHostEvent.CoHostLeft`                                                                                                           |
| Co-host removed        | `RoomRepository.onRoomParticipantRemoved(callback)`                               | `AmityCoHostEventType.coHostRemoved`                                                                                  | `AmityCoHostEvent.CoHostRemoved`                                                                                                        |
| Stage left             | `RoomRepository.onRoomParticipantStageLeft(callback)`                             | `AmityCoHostEventType.coHostStageLeft`                                                                                | No separate public sealed event in audited model                                                                                        |
| Product-tag permission | `updateCohostPermission(roomId, cohostId, canManageProductTags)`                  | `updateCohostPermissions(roomId:cohostId:canManageProductTags:)`                                                      | `updateCohostPermission(roomId, cohostId, canManageProductTags)`                                                                        |
| Remove participant     | `removeParticipant(roomId, participantUserId)`                                    | `removeParticipant(withId:userId:)`                                                                                   | `removeRoomParticipant(roomId, userId)`                                                                                                 |
| Leave room             | `leaveRoom(roomId)`                                                               | `leaveRoom(withId:)`                                                                                                  | `leaveRoom(roomId)`                                                                                                                     |

## Invite a Co-Host

Invite one user at a time. The invitation type is the room co-host invitation type under the hood.

<CodeGroup>
  ```typescript TypeScript theme={null}
  async function inviteCoHost(room: Amity.Room, cohostUserId: string) {
    await room.createInvitation(cohostUserId);
    showSuccessMessage(cohostUserId);
  }
  ```

  ```kotlin Android theme={null}
  import com.amity.socialcloud.sdk.model.video.room.AmityRoom

  fun inviteCoHost(room: AmityRoom, cohostUserId: String) {
      room.createInvitation(cohostUserId)
          .subscribe(
              { showSuccessMessage(cohostUserId) },
              { error -> handleGeneralError(error) }
          )
  }
  ```

  ```swift iOS theme={null}
  func inviteCoHost(room: AmityRoom, cohostUserId: String) async throws {
      try await room.createInvitation(cohostUserId)
      showSuccessMessage(cohostUserId)
  }
  ```
</CodeGroup>

## Respond or Cancel

Invited users accept or reject the pending invitation. Hosts cancel an invitation before it is accepted.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { InvitationRepository } from "@amityco/ts-sdk";

  async function acceptPendingRoomInvitation(room: Amity.Room) {
    const invitation = await room.getInvitations();

    if (invitation?.status === "pending") {
      await invitation.accept();
      showSuccessMessage(invitation.invitationId);
    }
  }

  async function cancelRoomInvitation(invitationId: string) {
    await InvitationRepository.cancelInvitation(invitationId);
    showSuccessMessage(invitationId);
  }
  ```

  ```kotlin Android theme={null}
  import com.amity.socialcloud.sdk.model.core.invitation.AmityInvitation
  import com.amity.socialcloud.sdk.model.video.room.AmityRoom
  import io.reactivex.rxjava3.core.Completable

  fun acceptPendingRoomInvitation(room: AmityRoom) {
      room.getInvitation()
          .flatMapCompletable { invitations ->
              invitations.firstOrNull()?.accept() ?: Completable.complete()
          }
          .subscribe(
              { showSuccessMessage(room.getRoomId()) },
              { error -> handleGeneralError(error) }
          )
  }

  fun cancelRoomInvitation(invitation: AmityInvitation) {
      invitation.cancel()
          .subscribe(
              { showSuccessMessage(invitation.getInvitationId()) },
              { error -> handleGeneralError(error) }
          )
  }
  ```

  ```swift iOS theme={null}
  func acceptPendingRoomInvitation(room: AmityRoom) async throws {
      guard let invitation = await room.getInvitation() else { return }

      if invitation.status == .pending {
          try await invitation.accept()
          showSuccessMessage(invitation.invitationId)
      }
  }

  func cancelRoomInvitation(room: AmityRoom, invitationId: String) async throws {
      try await room.cancelInvitation(invitationId)
      showSuccessMessage(invitationId)
  }
  ```
</CodeGroup>

## Observe Co-Host Events

Use invitation events for invite status and participant events for active room membership changes. Keep the returned unsubscribe, disposable, or cancellable for as long as the screen needs updates.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { InvitationRepository, RoomRepository } from "@amityco/ts-sdk";

  function observeCoHostEvents(roomId: string): Amity.Unsubscriber {
    const stopInvitationEvents = InvitationRepository.getInvitations(
      { targetId: roomId, targetType: "room" },
      invitations => {
        invitations.forEach(invitation => {
          showSuccessMessage(invitation.status);
        });
      },
    );

    const stopJoinedEvents = RoomRepository.onRoomParticipantJoined(event => {
      if (event.room.roomId === roomId) {
        showSuccessMessage(event.actorInternalId);
      }
    });

    const stopRemovedEvents = RoomRepository.onRoomParticipantRemoved(event => {
      if (event.room.roomId === roomId) {
        showSuccessMessage(event.actorInternalId);
      }
    });

    return () => {
      stopInvitationEvents();
      stopJoinedEvents();
      stopRemovedEvents();
    };
  }
  ```

  ```kotlin Android theme={null}
  import com.amity.socialcloud.sdk.api.video.AmityVideoClient
  import com.amity.socialcloud.sdk.core.session.model.AmityCoHostEvent

  val disposable = AmityVideoClient.newRoomRepository()
      .getCoHostEvent(roomId)
      .subscribe(
          { event ->
              when (event) {
                  is AmityCoHostEvent.CoHostInvited -> {
                      showSuccessMessage(event.invitation.getStatus())
                  }
                  is AmityCoHostEvent.CoHostJoined -> {
                      showSuccessMessage(event.actorInternalId ?: "")
                  }
                  is AmityCoHostEvent.CoHostRemoved -> {
                      showSuccessMessage(event.actorInternalId ?: "")
                  }
                  else -> {
                      showSuccessMessage(event.roomId)
                  }
              }
          },
          { error -> handleGeneralError(error) }
      )
  ```

  ```swift iOS theme={null}
  let roomRepository = AmityRoomRepository()
  var coHostEventCancellable: AnyCancellable?

  coHostEventCancellable = roomRepository
      .getCoHostEvent(roomId: roomId)
      .sink { event in
          switch event.type {
          case .invitationInvited,
               .invitationAccepted,
               .invitationRejected,
               .invitationCancelled:
              showSuccessMessage(event.invitation?.status.rawValue)
          case .coHostJoined,
               .coHostLeft,
               .coHostRemoved,
               .coHostStageLeft:
              showSuccessMessage(event.actorInternalId)
          default:
              showSuccessMessage(event.room.roomId)
          }
      }

  showSuccessMessage(coHostEventCancellable != nil)
  ```
</CodeGroup>

## Manage Active Co-Hosts

Hosts can update whether a co-host can manage product tags, remove a co-host from the room, and co-hosts can leave the room.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { RoomRepository } from "@amityco/ts-sdk";

  async function updateCoHostProductPermission(
    roomId: string,
    cohostUserId: string,
  ) {
    const { data: updatedRoom } = await RoomRepository.updateCohostPermission(
      roomId,
      cohostUserId,
      true,
    );

    showSuccessMessage(
      updatedRoom.participants.find(participant => participant.userId === cohostUserId)
        ?.canManageProductTags,
    );
  }

  async function removeCoHost(roomId: string, cohostUserId: string) {
    await RoomRepository.removeParticipant(roomId, cohostUserId);
    showSuccessMessage(cohostUserId);
  }

  async function leaveAsCoHost(roomId: string) {
    await RoomRepository.leaveRoom(roomId);
    showSuccessMessage(roomId);
  }
  ```

  ```kotlin Android theme={null}
  import com.amity.socialcloud.sdk.api.video.AmityVideoClient

  val roomRepository = AmityVideoClient.newRoomRepository()

  roomRepository.updateCohostPermission(
      roomId = roomId,
      cohostId = userId,
      canManageProductTags = true
  )
      .andThen(roomRepository.removeRoomParticipant(roomId, userId))
      .andThen(roomRepository.leaveRoom(roomId))
      .subscribe(
          { showSuccessMessage(roomId) },
          { error -> handleGeneralError(error) }
      )
  ```

  ```swift iOS theme={null}
  let roomRepository = AmityRoomRepository()

  let updatedRoom = try await roomRepository.updateCohostPermissions(
      roomId: roomId,
      cohostId: userId,
      canManageProductTags: true
  )
  showSuccessMessage(updatedRoom.roomId)

  try await roomRepository.removeParticipant(withId: roomId, userId: userId)

  _ = try await roomRepository.leaveRoom(withId: roomId)
  showSuccessMessage(roomId)
  ```
</CodeGroup>

<Info>
  TypeScript exposes room participant events as global room event subscribers, so filter by `event.room.roomId` when a screen only cares about one room. Android and iOS expose room-filtered co-host event streams from the room repository.
</Info>

## Broadcaster Data Boundary

Accepting a co-host invitation does not connect the app to LiveKit. After a user is ready to broadcast, request broadcaster data through the room repository and connect your media stack with the returned co-host URL and token.

| Platform   | Broadcaster data API                                                                                       |
| ---------- | ---------------------------------------------------------------------------------------------------------- |
| TypeScript | `RoomRepository.getBroadcasterData(roomId)` returns `coHostToken` and `coHostUrl` when available           |
| iOS        | `AmityRoomRepository().generateRoomToken(withId:)` returns room token data                                 |
| Android    | `AmityVideoClient.newRoomRepository().getBroadcasterData(roomId)` returns `AmityRoomBroadcastData.CoHosts` |
| Flutter    | No public room broadcasting repository found in this audit                                                 |

See [Start Broadcasting](./start-broadcasting) for media connection guidance.

## Related Topics

<CardGroup cols={3}>
  <Card title="Create Room" icon="plus" href="./create-room">
    Create a co-host room and seed its initial participant list.
  </Card>

  <Card title="Manage Rooms" icon="gear" href="./manage-rooms">
    Query, update, stop, delete, and observe rooms.
  </Card>

  <Card title="Start Broadcasting" icon="radio" href="./start-broadcasting">
    Connect the accepted host or co-host to the media stack.
  </Card>
</CardGroup>
