Disconnect a Specific Participant from a Conference Call via Genesys Cloud Conversations API
What You Will Build
- This tutorial demonstrates how to programmatically disconnect a specific participant from an active conference call using the Genesys Cloud CX Conversations API.
- You will use the
POST /api/v2/conversations/{conversationId}/participants/{participantId}/disconnectendpoint to terminate a participant’s session. - The implementation covers Python and JavaScript, handling authentication, participant identification, and error recovery.
Prerequisites
- OAuth Client: A Genesys Cloud OAuth Client ID and Client Secret with the
publicgrant type. - Required Scopes:
conversation:participant:writeis mandatory to modify participant state. - SDK Versions:
- Python:
genesys-cloud-sdkv12.0.0+ - JavaScript:
@genesyscloud/genesys-cloud-sdkv4.0.0+
- Python:
- Runtime:
- Python 3.9+
- Node.js 18+
- Dependencies:
- Python:
pip install genesys-cloud-sdk - JavaScript:
npm install @genesyscloud/genesys-cloud-sdk
- Python:
Authentication Setup
Genesys Cloud uses OAuth 2.0 for API authentication. You must obtain a valid access token before making API calls. The tokens expire after 3600 seconds (1 hour). In production, you should cache tokens and refresh them before expiration.
For this tutorial, we will use the Client Credentials Grant flow, which is standard for server-to-server integrations.
Python Authentication
import time
from purecloud_platform_client_v2 import Configuration, OAuthClient, ApiClient
def get_access_token(client_id: str, client_secret: str, base_url: str = "https://api.mypurecloud.com") -> str:
"""
Retrieves an OAuth access token using Client Credentials Grant.
"""
oauth_client = OAuthClient(
client_id=client_id,
client_secret=client_secret,
base_url=base_url
)
try:
# Request token with required scope
oauth_client.get_token(scope="conversation:participant:write")
return oauth_client.access_token
except Exception as e:
raise RuntimeError(f"Failed to obtain access token: {e}")
JavaScript Authentication
import { PlatformClient } from '@genesyscloud/genesys-cloud-sdk';
/**
* Initializes the platform client and authenticates.
* Note: The JS SDK handles token refresh automatically if configured correctly.
*/
let platformClient;
async function initPlatformClient(clientId, clientSecret, region = 'us-east-1') {
const baseUri = `https://api.${region}.mypurecloud.com`;
platformClient = new PlatformClient({
baseUri: baseUri,
clientId: clientId,
clientSecret: clientSecret
});
// Authenticate once at startup
await platformClient.auth.login({
grantType: 'client_credentials',
scope: ['conversation:participant:write']
});
return platformClient;
}
Implementation
Step 1: Identify the Conversation and Participant
Before disconnecting a participant, you must know the conversationId and the specific participantId. The participantId is a UUID generated when the participant joins the conversation.
If you do not have the participantId, you must query the conversation details first.
Fetching Conversation Details (Python)
from purecloud_platform_client_v2 import ConversationsApi, ApiClient, Configuration
def get_participants(conversation_id: str, access_token: str) -> list:
"""
Retrieves all participants in a specific conversation.
Returns a list of participant objects.
"""
configuration = Configuration(access_token=access_token)
api_client = ApiClient(configuration)
conversations_api = ConversationsApi(api_client)
try:
# Get the full conversation object including participants
response = conversations_api.get_conversation(conversation_id)
if not response.participants:
return []
return response.participants
except Exception as e:
# Handle 404 (Conversation not found) or 401 (Unauthorized)
print(f"Error fetching participants: {e}")
return []
Fetching Conversation Details (JavaScript)
async function getParticipants(conversationId) {
try {
// The SDK method returns a Promise resolving to the Conversation object
const conversation = await platformClient.conversations.getConversation({
conversationId: conversationId
});
if (!conversation.participants || conversation.participants.length === 0) {
return [];
}
return conversation.participants;
} catch (error) {
console.error(`Failed to fetch participants for conversation ${conversationId}:`, error);
throw error;
}
}
Step 2: Disconnect the Participant
The core action uses the POST /api/v2/conversations/{conversationId}/participants/{participantId}/disconnect endpoint.
Important Notes:
- The HTTP method is POST, not DELETE. This is a common point of confusion.
- The request body is optional. You can pass a
DisconnectParticipantRequestobject to specify a reason code or message, but it is not required for a basic disconnect. - If the participant is already disconnected, the API returns a 204 No Content or 404 Not Found depending on the state.
Python Implementation
from purecloud_platform_client_v2 import ConversationsApi, ApiClient, Configuration
from purecloud_platform_client_v2.models import DisconnectParticipantRequest
def disconnect_participant(conversation_id: str, participant_id: str, access_token: str, reason: str = None) -> bool:
"""
Disconnects a specific participant from a conversation.
Args:
conversation_id: The UUID of the conversation.
participant_id: The UUID of the participant to disconnect.
access_token: Valid OAuth access token.
reason: Optional reason for disconnect (e.g., 'agent_initiated').
Returns:
True if successful, False otherwise.
"""
configuration = Configuration(access_token=access_token)
api_client = ApiClient(configuration)
conversations_api = ConversationsApi(api_client)
try:
# Optional: Construct a body with a reason code
body = None
if reason:
body = DisconnectParticipantRequest(reason=reason)
# Execute the disconnect
# This endpoint returns 204 No Content on success
conversations_api.post_conversation_participant_disconnect(
conversation_id=conversation_id,
participant_id=participant_id,
body=body
)
return True
except Exception as e:
# Check for specific status codes
if hasattr(e, 'status') and e.status == 404:
print(f"Participant {participant_id} not found or already disconnected.")
elif hasattr(e, 'status') and e.status == 403:
print("Insufficient permissions. Ensure 'conversation:participant:write' scope is granted.")
else:
print(f"Error disconnecting participant: {e}")
return False
JavaScript Implementation
/**
* Disconnects a specific participant from a conversation.
*/
async function disconnectParticipant(conversationId, participantId, reason = null) {
try {
// Construct the body if a reason is provided
const body = reason ? { reason: reason } : undefined;
// Call the API
// The JS SDK method corresponds to POST /api/v2/conversations/{conversationId}/participants/{participantId}/disconnect
await platformClient.conversations.postConversationParticipantDisconnect({
conversationId: conversationId,
participantId: participantId,
body: body
});
console.log(`Successfully disconnected participant ${participantId}`);
return true;
} catch (error) {
if (error.status === 404) {
console.warn(`Participant ${participantId} not found in conversation ${conversationId}.`);
} else if (error.status === 403) {
console.error("Forbidden: Check OAuth scopes.");
} else {
console.error(`Failed to disconnect participant:`, error);
}
return false;
}
}
Step 3: Processing Results and Edge Cases
When disconnecting a participant, several edge cases must be handled:
- Participant Already Disconnected: If the participant has already left the call, the API may return a 404. This is not an error in business logic; it means the goal is already achieved.
- Conversation Ended: If the entire conversation has ended, the API returns a 404.
- Rate Limiting (429): Genesys Cloud enforces rate limits. If you receive a 429, you must wait before retrying. The
Retry-Afterheader indicates the wait time in seconds.
Handling Rate Limits in Python
import time
def disconnect_with_retry(conversation_id: str, participant_id: str, access_token: str, max_retries: int = 3) -> bool:
"""
Disconnects a participant with exponential backoff for 429 errors.
"""
configuration = Configuration(access_token=access_token)
api_client = ApiClient(configuration)
conversations_api = ConversationsApi(api_client)
for attempt in range(max_retries):
try:
conversations_api.post_conversation_participant_disconnect(
conversation_id=conversation_id,
participant_id=participant_id
)
return True
except Exception as e:
if hasattr(e, 'status') and e.status == 429:
wait_time = int(e.headers.get('Retry-After', 2 ** attempt))
print(f"Rate limited. Waiting {wait_time} seconds before retry...")
time.sleep(wait_time)
else:
# Non-retryable error
print(f"Non-retryable error: {e}")
return False
return False
Complete Working Example
This Python script combines authentication, participant lookup, and disconnection into a single workflow.
import sys
import time
from purecloud_platform_client_v2 import Configuration, OAuthClient, ApiClient, ConversationsApi
from purecloud_platform_client_v2.models import DisconnectParticipantRequest
# Configuration
CLIENT_ID = "YOUR_CLIENT_ID"
CLIENT_SECRET = "YOUR_CLIENT_SECRET"
BASE_URL = "https://api.mypurecloud.com"
CONVERSATION_ID = "YOUR_CONVERSATION_UUID"
PARTICIPANT_ID = "YOUR_PARTICIPANT_UUID" # Optional: If not provided, script will list participants
def main():
# 1. Authenticate
print("Authenticating...")
oauth_client = OAuthClient(
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
base_url=BASE_URL
)
try:
oauth_client.get_token(scope="conversation:participant:write")
access_token = oauth_client.access_token
print("Authentication successful.")
except Exception as e:
print(f"Authentication failed: {e}")
sys.exit(1)
# 2. Initialize API Client
configuration = Configuration(access_token=access_token)
api_client = ApiClient(configuration)
conversations_api = ConversationsApi(api_client)
# 3. Identify Participant (if not provided)
if not PARTICIPANT_ID:
print(f"Fetching participants for conversation {CONVERSATION_ID}...")
try:
conv = conversations_api.get_conversation(CONVERSATION_ID)
if not conv.participants:
print("No participants found in this conversation.")
sys.exit(0)
print("Available Participants:")
for p in conv.participants:
print(f" ID: {p.id}, Name: {p.name or 'Unknown'}, Type: {p.type}")
# For this example, we assume we want to disconnect the first participant
# In a real app, you would prompt the user or use a specific identifier
target_participant = conv.participants[0]
PARTICIPANT_ID = target_participant.id
print(f"Selected participant to disconnect: {PARTICIPANT_ID}")
except Exception as e:
print(f"Error fetching conversation: {e}")
sys.exit(1)
# 4. Disconnect Participant
print(f"Disconnecting participant {PARTICIPANT_ID} from conversation {CONVERSATION_ID}...")
try:
# Optional: Add a reason
body = DisconnectParticipantRequest(reason="administrative_disconnect")
conversations_api.post_conversation_participant_disconnect(
conversation_id=CONVERSATION_ID,
participant_id=PARTICIPANT_ID,
body=body
)
print("Participant disconnected successfully.")
except Exception as e:
if hasattr(e, 'status'):
if e.status == 404:
print("Participant not found or already disconnected.")
elif e.status == 403:
print("Permission denied. Check OAuth scopes.")
elif e.status == 429:
print("Rate limit exceeded. Try again later.")
else:
print(f"API Error {e.status}: {e.reason}")
else:
print(f"Unexpected error: {e}")
if __name__ == "__main__":
main()
Common Errors & Debugging
Error: 401 Unauthorized
- Cause: The access token is expired, invalid, or missing.
- Fix: Ensure you are calling
oauth_client.get_token()before making API requests. Check that your client ID and secret are correct. Verify that thescopeincludesconversation:participant:write.
Error: 403 Forbidden
- Cause: The OAuth client does not have the required permissions.
- Fix: Go to the Genesys Cloud Admin Console > Admin > Security > OAuth. Select your client and ensure
conversation:participant:writeis checked under Scopes. Save the changes. Note: You may need to regenerate the token after changing scopes.
Error: 404 Not Found
- Cause: The
conversationIdorparticipantIdis incorrect, or the participant has already disconnected. - Fix: Verify the UUIDs. Use the
GET /api/v2/conversations/{conversationId}endpoint to confirm the participant exists in theparticipantsarray. If the participant is already gone, treat this as a success condition in your logic.
Error: 429 Too Many Requests
- Cause: You have exceeded the API rate limit for your organization or client.
- Fix: Implement exponential backoff. Read the
Retry-Afterheader from the response to determine how long to wait. Do not retry immediately.
Error: 500 Internal Server Error
- Cause: A transient issue on the Genesys Cloud platform.
- Fix: Retry the request after a short delay (e.g., 1-2 seconds). If the error persists, check the Genesys Cloud status page for outages.