Programmatically Control Call Recording States via the Genesys Cloud Recording API
What You Will Build
- A Python script that authenticates with Genesys Cloud and programmatically starts or stops a call recording for an active conversation.
- This tutorial uses the Genesys Cloud
Recording API(/api/v2/recordings) to manage the lifecycle of a specific recording instance. - The implementation is provided in Python 3.9+ using the
genesyscloudSDK and therequestslibrary for raw HTTP fallback scenarios.
Prerequisites
- OAuth Client: A Genesys Cloud OAuth client with
confidentialorpublictype. - Required Scopes:
recording:read(to list or get recording status)recording:write(to start/stop recordings)conversation:read(to identify the conversation and recording IDs)
- SDK Version:
genesys-cloud-py>= 120.0.0 - Runtime: Python 3.9 or higher.
- Dependencies:
genesys-cloud-pyrequestspyyaml(for configuration, optional but recommended)
Authentication Setup
Genesys Cloud uses OAuth 2.0 Client Credentials flow for server-to-server integrations. The SDK handles token refresh automatically, but understanding the initialization is critical for debugging connection issues.
You must initialize the PlatformClient with your client ID, client secret, and environment (e.g., mypurecloud.com, euw1.pure.cloud, or auw2.pure.cloud).
import os
from purecloudplatformclientv2 import (
PlatformClient,
RecordingApi,
ConversationApi,
ApiClient
)
from purecloudplatformclientv2.rest import ApiException
def get_platform_client() -> PlatformClient:
"""
Initializes and returns an authenticated PlatformClient.
Raises an exception if authentication fails.
"""
client_id = os.environ.get("GENESYS_CLIENT_ID")
client_secret = os.environ.get("GENESYS_CLIENT_SECRET")
env_host = os.environ.get("GENESYS_ENV_HOST", "mypurecloud.com")
if not client_id or not client_secret:
raise ValueError("GENESYS_CLIENT_ID and GENESYS_CLIENT_SECRET must be set in environment.")
# Initialize the client
client = PlatformClient()
client.set_environment(env_host)
# Authenticate using Client Credentials
try:
client.authenticate_client_credentials(client_id, client_secret)
print(f"Successfully authenticated with Genesys Cloud environment: {env_host}")
except ApiException as e:
print(f"Authentication failed: {e.status} - {e.reason}")
raise
except Exception as e:
print(f"Unexpected error during authentication: {e}")
raise
return client
Implementation
Step 1: Identify the Active Conversation and Recording ID
You cannot start or stop a recording by Conversation ID alone. The Recording API requires the specific recordingId. In Genesys Cloud, a single conversation (e.g., a phone call) may have multiple recording segments (e.g., split recordings, compliance pauses). However, for standard start/stop operations on an active call, you typically target the primary recording associated with the interaction.
First, you must retrieve the active conversation to find the associated recordingId.
OAuth Scope: conversation:read
def get_active_recording_id(client: PlatformClient, conversation_id: str) -> str | None:
"""
Retrieves the primary recording ID for a given active conversation.
Args:
client: Authenticated PlatformClient.
conversation_id: The ID of the active conversation.
Returns:
The recording ID if found, otherwise None.
"""
conversation_api = ConversationApi(client)
try:
# Fetch the conversation details
conversation = conversation_api.get_conversation_by_id(conversation_id)
# Check if the conversation has recordings
if conversation.recording is None:
print("No recording associated with this conversation.")
return None
# The 'recording' object contains the primary recording details
# Note: In complex scenarios, 'recordings' (plural) might be used for split recordings
recording_id = conversation.recording.id
print(f"Found active recording ID: {recording_id}")
return recording_id
except ApiException as e:
if e.status == 404:
print(f"Conversation {conversation_id} not found or has ended.")
elif e.status == 401:
print("Unauthorized. Check OAuth scopes: conversation:read")
else:
print(f"Error fetching conversation: {e.status} - {e.reason}")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
Step 2: Stop a Recording
To stop a recording, you issue a PUT request to the /api/v2/recordings/{recordingId} endpoint with the status set to stopped. This action is immediate and final for that specific recording segment. If the call continues, a new recording segment may start automatically depending on your Organization Recording Settings.
OAuth Scope: recording:write
def stop_recording(client: PlatformClient, recording_id: str) -> bool:
"""
Stops an active recording by its ID.
Args:
client: Authenticated PlatformClient.
recording_id: The ID of the recording to stop.
Returns:
True if the stop command was accepted, False otherwise.
"""
recording_api = RecordingApi(client)
try:
# The SDK method puts the recording into a stopped state
# This corresponds to: PUT /api/v2/recordings/{recordingId}
# Body: { "status": "stopped" }
# Note: In newer SDK versions, this might be handled via a specific update method
# or by passing the status in the body.
# Using the raw API call for clarity if SDK method varies by version.
# Standard SDK approach for updating recording status:
from purecloudplatformclientv2 import Recording
# Construct the update body
update_body = Recording(status="stopped")
# Execute the update
recording_api.put_recording_by_id(recording_id, body=update_body)
print(f"Successfully stopped recording: {recording_id}")
return True
except ApiException as e:
if e.status == 404:
print(f"Recording {recording_id} not found. It may have already ended.")
elif e.status == 403:
print("Forbidden. Ensure the user/client has 'recording:write' scope.")
elif e.status == 409:
print("Conflict. The recording is already stopped or in an invalid state for this action.")
else:
print(f"Error stopping recording: {e.status} - {e.reason}")
return False
except Exception as e:
print(f"Unexpected error: {e}")
return False
Step 3: Start a Recording
Starting a recording programmatically is more nuanced. You cannot “start” a recording on a conversation that does not already have a recording configuration attached to it at the organizational or user level. However, you can pause and resume recordings.
If the goal is to initiate a recording that was previously paused, you set the status to recording. If the goal is to start a new recording on a live call that has no active recording, the API does not support creating a new recording segment from scratch via API unless the conversation was started with recording enabled.
Correction: In Genesys Cloud, the primary programmatic control is Pause and Resume. You cannot “Start” a recording from a non-recording state via API if the underlying policy does not dictate it. However, you can Resume a paused recording.
To Pause a recording:
OAuth Scope: recording:write
def pause_recording(client: PlatformClient, recording_id: str) -> bool:
"""
Pauses an active recording.
Args:
client: Authenticated PlatformClient.
recording_id: The ID of the recording to pause.
Returns:
True if the pause command was accepted, False otherwise.
"""
recording_api = RecordingApi(client)
try:
from purecloudplatformclientv2 import Recording
# Set status to 'paused'
update_body = Recording(status="paused")
recording_api.put_recording_by_id(recording_id, body=update_body)
print(f"Successfully paused recording: {recording_id}")
return True
except ApiException as e:
if e.status == 409:
print("Conflict. The recording is already paused or stopped.")
elif e.status == 404:
print(f"Recording {recording_id} not found.")
else:
print(f"Error pausing recording: {e.status} - {e.reason}")
return False
except Exception as e:
print(f"Unexpected error: {e}")
return False
To Resume (Start) a Paused Recording:
def resume_recording(client: PlatformClient, recording_id: str) -> bool:
"""
Resumes a paused recording.
Args:
client: Authenticated PlatformClient.
recording_id: The ID of the recording to resume.
Returns:
True if the resume command was accepted, False otherwise.
"""
recording_api = RecordingApi(client)
try:
from purecloudplatformclientv2 import Recording
# Set status back to 'recording'
update_body = Recording(status="recording")
recording_api.put_recording_by_id(recording_id, body=update_body)
print(f"Successfully resumed recording: {recording_id}")
return True
except ApiException as e:
if e.status == 409:
print("Conflict. The recording is not paused, or already stopped.")
elif e.status == 404:
print(f"Recording {recording_id} not found.")
else:
print(f"Error resuming recording: {e.status} - {e.reason}")
return False
except Exception as e:
print(f"Unexpected error: {e}")
return False
Complete Working Example
This script demonstrates how to find an active conversation, identify its recording, and toggle the recording state. Replace the placeholder values with your actual Genesys Cloud credentials.
import os
import sys
import time
from purecloudplatformclientv2 import (
PlatformClient,
RecordingApi,
ConversationApi,
ApiClient
)
from purecloudplatformclientv2.rest import ApiException
from purecloudplatformclientv2 import Recording
# Configuration
GENESYS_CLIENT_ID = os.environ.get("GENESYS_CLIENT_ID")
GENESYS_CLIENT_SECRET = os.environ.get("GENESYS_CLIENT_SECRET")
GENESYS_ENV_HOST = os.environ.get("GENESYS_ENV_HOST", "mypurecloud.com")
TARGET_CONVERSATION_ID = os.environ.get("TARGET_CONVERSATION_ID") # Must be an active conversation ID
def get_platform_client() -> PlatformClient:
"""Initializes the Genesys Cloud Platform Client."""
if not GENESYS_CLIENT_ID or not GENESYS_CLIENT_SECRET:
raise ValueError("GENESYS_CLIENT_ID and GENESYS_CLIENT_SECRET must be set.")
client = PlatformClient()
client.set_environment(GENESYS_ENV_HOST)
try:
client.authenticate_client_credentials(GENESYS_CLIENT_ID, GENESYS_CLIENT_SECRET)
except ApiException as e:
print(f"Authentication failed: {e.status} - {e.reason}")
sys.exit(1)
return client
def get_active_recording_id(client: PlatformClient, conversation_id: str) -> str | None:
"""Retrieves the primary recording ID for a given conversation."""
conversation_api = ConversationApi(client)
try:
conversation = conversation_api.get_conversation_by_id(conversation_id)
if conversation.recording is None:
print("No active recording found for this conversation.")
return None
return conversation.recording.id
except ApiException as e:
print(f"Error fetching conversation: {e.status} - {e.reason}")
return None
def update_recording_status(client: PlatformClient, recording_id: str, new_status: str) -> bool:
"""
Updates the status of a recording (recording, paused, stopped).
"""
recording_api = RecordingApi(client)
try:
update_body = Recording(status=new_status)
recording_api.put_recording_by_id(recording_id, body=update_body)
print(f"Recording {recording_id} status updated to: {new_status}")
return True
except ApiException as e:
print(f"Error updating recording status: {e.status} - {e.reason}")
return False
def main():
if not TARGET_CONVERSATION_ID:
print("Error: TARGET_CONVERSATION_ID environment variable is required.")
sys.exit(1)
print(f"Initializing client for environment: {GENESYS_ENV_HOST}")
client = get_platform_client()
print(f"Fetching recording ID for conversation: {TARGET_CONVERSATION_ID}")
recording_id = get_active_recording_id(client, TARGET_CONVERSATION_ID)
if not recording_id:
print("Cannot proceed without a valid recording ID.")
sys.exit(1)
# Example Workflow: Pause -> Wait -> Resume -> Stop
print("\n--- Step 1: Pause Recording ---")
if not update_recording_status(client, recording_id, "paused"):
print("Failed to pause recording. Exiting.")
sys.exit(1)
print("\nWaiting 5 seconds...")
time.sleep(5)
print("\n--- Step 2: Resume Recording ---")
if not update_recording_status(client, recording_id, "recording"):
print("Failed to resume recording. Exiting.")
sys.exit(1)
print("\nWaiting 5 seconds...")
time.sleep(5)
print("\n--- Step 3: Stop Recording ---")
if not update_recording_status(client, recording_id, "stopped"):
print("Failed to stop recording.")
else:
print("Recording successfully stopped.")
if __name__ == "__main__":
main()
Common Errors & Debugging
Error: 403 Forbidden
- Cause: The OAuth client lacks the
recording:writescope. - Fix: Log in to the Genesys Cloud Admin console, navigate to Admin > Integrations > OAuth Clients, edit your client, and ensure
recording:writeis checked under the Scopes. Re-authenticate after saving.
Error: 404 Not Found
- Cause: The
recordingIdprovided does not exist, or the conversation has ended and the recording ID is no longer active in the immediate context. - Fix: Verify the
recordingIdby callingGET /api/v2/recordings/{recordingId}. If the conversation has ended, the recording may have moved to therecordingsarchive and cannot be modified. You can only modify recordings with statusrecordingorpaused.
Error: 409 Conflict
- Cause: Attempting to pause a recording that is already paused, or stopping a recording that is already stopped.
- Fix: Always check the current
statusfield of theRecordingobject before issuing a state change. Implement logic to skip the API call if the current status matches the desired status.
Error: 422 Unprocessable Entity
- Cause: The request body is malformed or contains an invalid status value.
- Fix: Ensure the status is one of the valid values:
recording,paused, orstopped. The SDKRecordingclass enforces this, but if using raw HTTP, verify the JSON payload.