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

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

What You Will Build

  • One sentence: A script that identifies a specific participant within an active conference call and programmatically disconnects them.
  • One sentence: This uses the Genesys Cloud CX Conversations API (/api/v2/conversations/conferences).
  • One sentence: The primary implementation is in Python using the genesys-cloud-sdk, with HTTP fallback examples.

Prerequisites

  • OAuth Client Type: Service Account or OAuth2 Client Credentials flow.
  • Required Scopes:
    • conversation:participant:delete (Required to remove participants).
    • conversation:view (Required to retrieve the conference details to identify the participant).
  • SDK Version: Genesys Cloud Python SDK v4.0.0 or later.
  • Language/Runtime: Python 3.8+.
  • External Dependencies:
    • genesys-cloud-sdk
    • python-dotenv (for managing credentials securely)

Authentication Setup

The Genesys Cloud SDK handles OAuth token acquisition and refresh automatically when initialized correctly. You must configure your environment variables before running the code.

Create a .env file in your project root:

GENESYS_CLOUD_REGION=us-east-1
GENESYS_CLOUD_CLIENT_ID=your-client-id
GENESYS_CLOUD_CLIENT_SECRET=your-client-secret

Initialize the SDK client. This example uses the PureCloudPlatformClientV2 which is the entry point for all API calls.

import os
from dotenv import load_dotenv
from purecloud_platform_client import PureCloudPlatformClientV2
from purecloud_platform_client.rest import ApiException

# Load environment variables
load_dotenv()

def get_platform_client() -> PureCloudPlatformClientV2:
    """
    Initializes and returns the authenticated Genesys Cloud platform client.
    """
    client = PureCloudPlatformClientV2()

    # Configure OAuth2 client credentials flow
    client.set_environment(os.getenv("GENESYS_CLOUD_REGION"))
    client.set_oauth_client_credentials(
        os.getenv("GENESYS_CLOUD_CLIENT_ID"),
        os.getenv("GENESYS_CLOUD_CLIENT_SECRET")
    )

    return client

Implementation

Step 1: Retrieve the Active Conference

You cannot disconnect a participant without knowing the conferenceId and the participantId (or externalContactId/userId) of the target. The first step is to query the active conferences.

The endpoint GET /api/v2/conversations/conferences returns a list of active conferences. For simplicity, this example assumes you know the conversationId of the call you want to modify. If you do not know the conversationId, you must query /api/v2/conversations/details/query first to find the active conversation.

Here we assume you have the conversationId. We will fetch the conference details to list all participants.

from purecloud_platform_client import ConversationApi

def get_conference_details(platform_client: PureCloudPlatformClientV2, conversation_id: str) -> dict:
    """
    Retrieves the full conference object for a specific conversation.
    
    Args:
        platform_client: The initialized SDK client.
        conversation_id: The unique ID of the active conversation.
        
    Returns:
        A dictionary containing the conference details.
    """
    api_instance = ConversationApi(platform_client)
    
    try:
        # The SDK method maps to GET /api/v2/conversations/conferences/{conversationId}
        response = api_instance.get_conversations_conference(
            conversation_id=conversation_id
        )
        
        # The response is a Conference object. We convert it to a dict for easier inspection 
        # in this tutorial, though in production you should use the typed object properties.
        return response.to_dict()
        
    except ApiException as e:
        print(f"Exception when calling ConversationApi->get_conversations_conference: {e}")
        raise

Expected Response Structure (Simplified):

{
  "conferenceId": "conf-12345",
  "conversationId": "conv-67890",
  "participants": [
    {
      "participantId": "part-001",
      "userId": "user-abc",
      "name": "Agent Smith",
      "status": "active"
    },
    {
      "participantId": "part-002",
      "externalContactId": "ext-xyz",
      "name": "Customer John Doe",
      "status": "active"
    }
  ]
}

Step 2: Identify the Target Participant

You must filter the participants list to find the specific person you wish to disconnect. You can identify them by userId (for agents) or externalContactId (for customers).

This function iterates through the participants and returns the participantId of the target.

def find_participant_id(conference_data: dict, target_user_id: str = None, target_external_contact_id: str = None) -> str | None:
    """
    Finds the participantId for a specific user or external contact.
    
    Args:
        conference_data: The dictionary returned from get_conference_details.
        target_user_id: The userId of the agent to disconnect.
        target_external_contact_id: The externalContactId of the customer to disconnect.
        
    Returns:
        The participantId string, or None if not found.
    """
    participants = conference_data.get("participants", [])
    
    for participant in participants:
        # Check if it is an agent
        if target_user_id and participant.get("userId") == target_user_id:
            return participant.get("participantId")
        
        # Check if it is an external contact (customer)
        if target_external_contact_id and participant.get("externalContactId") == target_external_contact_id:
            return participant.get("participantId")
            
    return None

Step 3: Execute the Disconnect

Once you have the conferenceId and the participantId, you call the delete participant endpoint.

The SDK method delete_conversations_conference_participant maps to:
DELETE /api/v2/conversations/conferences/{conferenceId}/participants/{participantId}

Scope Required: conversation:participant:delete

def disconnect_participant(platform_client: PureCloudPlatformClientV2, conference_id: str, participant_id: str) -> bool:
    """
    Disconnects a specific participant from a conference.
    
    Args:
        platform_client: The initialized SDK client.
        conference_id: The ID of the conference.
        participant_id: The ID of the participant to remove.
        
    Returns:
        True if successful, False otherwise.
    """
    api_instance = ConversationApi(platform_client)
    
    try:
        # This performs a DELETE request. 
        # It does not return a body on success, just a 204 No Content status.
        api_instance.delete_conversations_conference_participant(
            conference_id=conference_id,
            participant_id=participant_id
        )
        
        print(f"Successfully disconnected participant {participant_id} from conference {conference_id}")
        return True
        
    except ApiException as e:
        # Handle specific error codes
        if e.status == 404:
            print(f"Error 404: Conference or Participant not found. Conference: {conference_id}, Participant: {participant_id}")
        elif e.status == 403:
            print(f"Error 403: Forbidden. Ensure the OAuth token has 'conversation:participant:delete' scope.")
        elif e.status == 429:
            print(f"Error 429: Rate limit exceeded. Retry after delay.")
        else:
            print(f"Exception when deleting participant: {e}")
        return False

Complete Working Example

This script combines all steps. It authenticates, finds a conversation by ID, locates a participant by their userId or externalContactId, and disconnects them.

import os
import sys
from dotenv import load_dotenv
from purecloud_platform_client import PureCloudPlatformClientV2, ConversationApi
from purecloud_platform_client.rest import ApiException

load_dotenv()

def main():
    # 1. Configuration
    conversation_id = os.getenv("TARGET_CONVERSATION_ID")
    target_user_id = os.getenv("TARGET_USER_ID")  # Optional: Agent ID
    target_external_contact_id = os.getenv("TARGET_EXTERNAL_CONTACT_ID") # Optional: Customer ID

    if not conversation_id:
        print("Error: TARGET_CONVERSATION_ID environment variable is required.")
        sys.exit(1)
    
    if not target_user_id and not target_external_contact_id:
        print("Error: Either TARGET_USER_ID or TARGET_EXTERNAL_CONTACT_ID is required.")
        sys.exit(1)

    # 2. Initialize Client
    platform_client = PureCloudPlatformClientV2()
    platform_client.set_environment(os.getenv("GENESYS_CLOUD_REGION"))
    platform_client.set_oauth_client_credentials(
        os.getenv("GENESYS_CLOUD_CLIENT_ID"),
        os.getenv("GENESYS_CLOUD_CLIENT_SECRET")
    )

    api_instance = ConversationApi(platform_client)

    try:
        # 3. Get Conference Details
        print(f"Fetching conference details for conversation: {conversation_id}")
        conference_response = api_instance.get_conversations_conference(conversation_id)
        conference_data = conference_response.to_dict()
        
        conference_id = conference_data.get("conferenceId")
        if not conference_id:
            print("Error: Could not retrieve conferenceId from response.")
            sys.exit(1)
            
        print(f"Found Conference ID: {conference_id}")

        # 4. Identify Participant
        participants = conference_data.get("participants", [])
        target_participant_id = None
        
        for p in participants:
            if target_user_id and p.get("userId") == target_user_id:
                target_participant_id = p.get("participantId")
                print(f"Found Agent Participant ID: {target_participant_id}")
                break
            elif target_external_contact_id and p.get("externalContactId") == target_external_contact_id:
                target_participant_id = p.get("participantId")
                print(f"Found External Contact Participant ID: {target_participant_id}")
                break
        
        if not target_participant_id:
            print("Error: Target participant not found in this conference.")
            sys.exit(1)

        # 5. Disconnect Participant
        print(f"Disconnecting participant {target_participant_id}...")
        api_instance.delete_conversations_conference_participant(
            conference_id=conference_id,
            participant_id=target_participant_id
        )
        print("Success: Participant disconnected.")

    except ApiException as e:
        print(f"API Exception occurred: {e.status} {e.reason}")
        print(f"Response body: {e.body}")
        sys.exit(1)
    except Exception as e:
        print(f"Unexpected error: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()

Common Errors & Debugging

Error: 403 Forbidden

What causes it:
The OAuth token used to make the request lacks the conversation:participant:delete scope. This is the most common error when developers use a generic “view” scope.

How to fix it:

  1. Go to the Genesys Cloud Admin Console.
  2. Navigate to Security > OAuth clients.
  3. Edit your client.
  4. Under Scopes, ensure conversation:participant:delete is checked.
  5. Regenerate the token or restart your application to pick up the new scope permissions.

Code Check:
Verify your .env client credentials match the client with the correct scopes.

Error: 404 Not Found

What causes it:

  1. The conversationId is incorrect or the conversation has already ended.
  2. The conferenceId retrieved does not match the active conference (rare, but possible if the conversation was bridged or transferred recently).
  3. The participantId is incorrect or the participant has already left the call.

How to fix it:
Ensure the conversation is currently active. You can verify this by checking the status field in the conference response. If the status is ended, you cannot disconnect participants.

# Add this check before attempting disconnect
status = conference_data.get("status")
if status != "active":
    print(f"Cannot disconnect. Conference status is: {status}")

Error: 409 Conflict

What causes it:
The participant is in a state that prevents disconnection, such as being in the process of being transferred or holding a lock on the conference (e.g., merging calls).

How to fix it:
Wait a few seconds and retry. Ensure no other operations are modifying the conference simultaneously.

Error: 429 Too Many Requests

What causes it:
You have exceeded the rate limit for the Conversations API. The default limit is typically 20 requests per second for this endpoint, but it varies by organization tier.

How to fix it:
Implement exponential backoff. The Genesys Cloud SDK does not auto-retry 429s by default in all methods, so you must handle it in your loop.

import time

def safe_disconnect(api_instance, conference_id, participant_id, max_retries=3):
    for attempt in range(max_retries):
        try:
            api_instance.delete_conversations_conference_participant(
                conference_id=conference_id,
                participant_id=participant_id
            )
            return True
        except ApiException as e:
            if e.status == 429:
                wait_time = 2 ** attempt
                print(f"Rate limited. Waiting {wait_time} seconds before retry...")
                time.sleep(wait_time)
            else:
                raise
    return False

Official References