How to Disconnect a Specific Participant from a Conference Call Using the Genesys Cloud Conversations API

How to Disconnect a Specific Participant from a Conference Call Using the Genesys Cloud Conversations API

What You Will Build

  • A script that identifies a specific participant within an active conference conversation and forcibly disconnects them using the Genesys Cloud API.
  • This tutorial uses the Genesys Cloud Platform Client SDK (Python) and direct REST API calls via requests.
  • The implementation covers Python, with concepts applicable to JavaScript/TypeScript and Java environments.

Prerequisites

  • OAuth Client Type: Service Account or JWT Client.
  • Required Scopes: conversation:participant:write, conversation:read.
  • SDK Version: Genesys Cloud Python SDK @genesyscloud/genesyscloud-python (v2.x+).
  • Runtime: Python 3.8+.
  • Dependencies: genesys-cloud, requests, python-dotenv.

Authentication Setup

Genesys Cloud APIs require OAuth 2.0 authentication. For server-side integrations, a Service Account or JWT client is recommended. The following example demonstrates initializing the Genesys Cloud Platform Client using environment variables.

import os
from dotenv import load_dotenv
from purecloudplatformclientv2 import Configuration, ApiClient

# Load environment variables from .env file
load_dotenv()

def get_platform_client():
    """
    Initializes and returns the Genesys Cloud Platform Client.
    """
    # Configuration for the API client
    configuration = Configuration(
        host=os.getenv("GENESYS_CLOUD_BASE_URL", "https://api.mypurecloud.com"),
        client_id=os.getenv("GENESYS_CLOUD_CLIENT_ID"),
        client_secret=os.getenv("GENESYS_CLOUD_CLIENT_SECRET")
    )

    # Create the API client instance
    api_client = ApiClient(configuration)
    return api_client

Ensure your .env file contains:

GENESYS_CLOUD_CLIENT_ID=your_client_id
GENESYS_CLOUD_CLIENT_SECRET=your_client_secret
GENESYS_CLOUD_BASE_URL=https://api.mypurecloud.com

Implementation

Step 1: Retrieve the Conversation Details

Before disconnecting a participant, you must identify the specific participantId associated with the user you wish to remove. The conversation ID is typically known from your application context (e.g., passed via a webhook or stored in your database).

The GET /api/v2/conversations/{conversationId} endpoint returns the full conversation object, including the participants array. Each participant object contains a unique id and metadata such as name and externalId.

from purecloudplatformclientv2 import ConversationApi, ApiException
from typing import Optional

def get_conversation_participants(api_client: ApiClient, conversation_id: str) -> Optional[dict]:
    """
    Fetches the conversation details and returns the participants list.
    
    Args:
        api_client: The initialized Genesys Cloud API client.
        conversation_id: The UUID of the active conversation.
        
    Returns:
        A dictionary containing the participants list or None if an error occurs.
    """
    conversation_api = ConversationApi(api_client)
    
    try:
        # Fetch the full conversation object
        conversation = conversation_api.get_conversation(conversation_id)
        
        if not conversation or not conversation.participants:
            print(f"No participants found in conversation {conversation_id}")
            return None
            
        return {
            "conversation_id": conversation_id,
            "participants": conversation.participants
        }
        
    except ApiException as e:
        if e.status == 404:
            print(f"Conversation {conversation_id} not found.")
        elif e.status == 401 or e.status == 403:
            print(f"Authentication or permission error: {e.reason}")
        else:
            print(f"API Error: {e.status} - {e.reason}")
        return None

Step 2: Identify the Target Participant

In a conference call, multiple participants may share the same name or have no name at all. You must match against a reliable identifier. The externalId is often the most robust field if you set it during participant creation. If externalId is not available, match against name and type (e.g., agent, user, external).

The following function iterates through the participants and returns the participantId for the target user.

def find_target_participant(participants_data: dict, target_identifier: str, identifier_type: str = "external_id") -> Optional[str]:
    """
    Finds the participant ID based on a specific identifier.
    
    Args:
        participants_data: The data returned from get_conversation_participants.
        target_identifier: The value to match (e.g., 'user_123', 'John Doe').
        identifier_type: 'external_id' or 'name'.
        
    Returns:
        The participantId string or None if not found.
    """
    participants = participants_data.get("participants", [])
    
    for participant in participants:
        if identifier_type == "external_id":
            if participant.external_id == target_identifier:
                return participant.id
        elif identifier_type == "name":
            if participant.name == target_identifier:
                return participant.id
                
    return None

Step 3: Disconnect the Participant

To disconnect a participant, you must send a POST request to /api/v2/conversations/{conversationId}/participants/{participantId}/disconnect. This endpoint requires the participantId and the conversationId.

The request body is typically empty for a standard disconnect, but you can include a reason code in some contexts. The primary action is the HTTP POST to the disconnect endpoint.

from purecloudplatformclientv2 import ConversationParticipantApi

def disconnect_participant(api_client: ApiClient, conversation_id: str, participant_id: str) -> bool:
    """
    Disconnects a specific participant from a conversation.
    
    Args:
        api_client: The initialized Genesys Cloud API client.
        conversation_id: The UUID of the conversation.
        participant_id: The UUID of the participant to disconnect.
        
    Returns:
        True if successful, False otherwise.
    """
    conversation_participant_api = ConversationParticipantApi(api_client)
    
    try:
        # The disconnect method in the SDK maps to POST /api/v2/conversations/{conversationId}/participants/{participantId}/disconnect
        # It does not require a request body for basic disconnection.
        conversation_participant_api.post_conversation_participant_disconnect(
            conversation_id=conversation_id,
            participant_id=participant_id
        )
        
        print(f"Successfully disconnected participant {participant_id} from conversation {conversation_id}")
        return True
        
    except ApiException as e:
        if e.status == 404:
            print(f"Participant {participant_id} or Conversation {conversation_id} not found.")
        elif e.status == 409:
            print(f"Conflict: Participant may already be disconnected or in a terminal state.")
        elif e.status == 429:
            print(f"Rate limit exceeded. Retry later.")
        else:
            print(f"API Error during disconnect: {e.status} - {e.reason}")
        return False

Complete Working Example

The following script combines all steps into a single executable module. It loads credentials, fetches the conversation, identifies the participant by externalId, and disconnects them.

import os
from dotenv import load_dotenv
from purecloudplatformclientv2 import Configuration, ApiClient, ConversationApi, ConversationParticipantApi, ApiException
from typing import Optional

# Load environment variables
load_dotenv()

def get_platform_client() -> ApiClient:
    """Initializes the Genesys Cloud API Client."""
    configuration = Configuration(
        host=os.getenv("GENESYS_CLOUD_BASE_URL", "https://api.mypurecloud.com"),
        client_id=os.getenv("GENESYS_CLOUD_CLIENT_ID"),
        client_secret=os.getenv("GENESYS_CLOUD_CLIENT_SECRET")
    )
    return ApiClient(configuration)

def get_conversation_participants(api_client: ApiClient, conversation_id: str) -> Optional[list]:
    """Fetches participants from a conversation."""
    conversation_api = ConversationApi(api_client)
    try:
        conversation = conversation_api.get_conversation(conversation_id)
        return conversation.participants if conversation else []
    except ApiException as e:
        print(f"Error fetching conversation: {e.status} - {e.reason}")
        return None

def find_participant_id(participants: list, target_external_id: str) -> Optional[str]:
    """Finds participant ID by externalId."""
    for participant in participants:
        if participant.external_id == target_external_id:
            return participant.id
    return None

def disconnect_participant(api_client: ApiClient, conversation_id: str, participant_id: str) -> bool:
    """Disconnects a participant from a conversation."""
    conversation_participant_api = ConversationParticipantApi(api_client)
    try:
        conversation_participant_api.post_conversation_participant_disconnect(
            conversation_id=conversation_id,
            participant_id=participant_id
        )
        print(f"Participant {participant_id} disconnected successfully.")
        return True
    except ApiException as e:
        print(f"Error disconnecting participant: {e.status} - {e.reason}")
        return False

def main():
    # Configuration
    CONVERSATION_ID = os.getenv("TARGET_CONVERSATION_ID")
    TARGET_EXTERNAL_ID = os.getenv("TARGET_PARTICIPANT_EXTERNAL_ID")
    
    if not CONVERSATION_ID or not TARGET_EXTERNAL_ID:
        print("Please set TARGET_CONVERSATION_ID and TARGET_PARTICIPANT_EXTERNAL_ID in .env")
        return

    # Initialize Client
    api_client = get_platform_client()
    
    # Step 1: Get Participants
    print(f"Fetching participants for conversation {CONVERSATION_ID}...")
    participants = get_conversation_participants(api_client, CONVERSATION_ID)
    
    if not participants:
        print("Failed to retrieve participants.")
        return

    # Step 2: Find Target Participant
    print(f"Searching for participant with externalId: {TARGET_EXTERNAL_ID}")
    participant_id = find_participant_id(participants, TARGET_EXTERNAL_ID)
    
    if not participant_id:
        print(f"Participant with externalId '{TARGET_EXTERNAL_ID}' not found in conversation.")
        return

    # Step 3: Disconnect
    print(f"Disconnecting participant {participant_id}...")
    success = disconnect_participant(api_client, CONVERSATION_ID, participant_id)
    
    if success:
        print("Operation completed successfully.")
    else:
        print("Operation failed.")

if __name__ == "__main__":
    main()

Common Errors & Debugging

Error: 404 Not Found

  • Cause: The conversationId does not exist, or the participantId is invalid.
  • Fix: Verify the conversationId is active. Check if the participant has already been disconnected by another process.
  • Code Check: Ensure you are using the correct conversationId from the Genesys Cloud platform.

Error: 403 Forbidden

  • Cause: The OAuth token lacks the conversation:participant:write scope.
  • Fix: Update your OAuth client permissions in the Genesys Cloud Admin Console.
  • Code Check: Verify the Configuration object uses a client with the correct scopes.

Error: 409 Conflict

  • Cause: The participant is already in a terminated or disconnected state.
  • Fix: Check the state field of the participant object before attempting disconnect.
  • Code Check:
    if participant.state == "terminated":
        print("Participant already disconnected.")
        return
    

Error: 429 Too Many Requests

  • Cause: Rate limiting due to high API call volume.
  • Fix: Implement exponential backoff retry logic.
  • Code Check: Use a library like tenacity for retries.
    from tenacity import retry, wait_exponential, stop_after_attempt
    
    @retry(wait=wait_exponential(multiplier=1, min=2, max=10), stop=stop_after_attempt(3))
    def disconnect_participant_with_retry(api_client, conversation_id, participant_id):
        # ... disconnect logic ...
    

Official References