How to Initiate a Cobrowse Session Programmatically via Genesys Cloud CX API
What You Will Build
You will build a backend service that initiates a cobrowse session for a specific user or agent within Genesys Cloud CX.
This tutorial uses the Genesys Cloud CX Conversations API and the cobrowse resource group.
The implementation is provided in Python using the official genesyscloud SDK and raw HTTP requests for transparency.
Prerequisites
- OAuth Client Credentials: You need a Genesys Cloud application with the
client_credentialsgrant type. - Required OAuth Scopes:
cobrowse:session:write(to initiate the session)cobrowse:session:read(to retrieve session status/details)user:read(if you need to resolve user IDs from emails)
- SDK Version:
genesyscloudPython SDK version 145.0.0 or higher. - Runtime: Python 3.9+.
- Dependencies:
genesyscloudrequests(for raw HTTP examples)
Install the dependencies:
pip install genesyscloud requests
Authentication Setup
Genesys Cloud CX uses OAuth 2.0. For server-to-server integrations, the client_credentials flow is the standard. You must exchange your client ID and client secret for an access token before making any API calls.
The following Python class handles token acquisition and caching. It ensures you do not hit rate limits by requesting new tokens unnecessarily.
import requests
import time
import os
from typing import Optional, Dict
class GenesysAuth:
def __init__(self, client_id: str, client_secret: str, environment: str = "mypurecloud.com"):
self.client_id = client_id
self.client_secret = client_secret
self.environment = environment
self.base_url = f"https://{environment}"
self.token_url = f"{self.base_url}/oauth/token"
self.access_token: Optional[str] = None
self.token_expiry: float = 0
def get_access_token(self) -> str:
"""
Retrieves an OAuth access token.
Returns a cached token if it is still valid.
"""
# Check if token is still valid (add 60s buffer for clock skew)
if self.access_token and time.time() < (self.token_expiry - 60):
return self.access_token
# Request new token
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
data = {
"grant_type": "client_credentials",
"client_id": self.client_id,
"client_secret": self.client_secret
}
try:
response = requests.post(self.token_url, headers=headers, data=data)
response.raise_for_status()
token_data = response.json()
self.access_token = token_data["access_token"]
self.token_expiry = time.time() + token_data["expires_in"]
return self.access_token
except requests.exceptions.HTTPError as e:
raise Exception(f"Failed to authenticate with Genesys Cloud: {e.response.text}")
except Exception as e:
raise Exception(f"Authentication error: {str(e)}")
# Usage Example
# auth = GenesysAuth(
# client_id=os.getenv("GENESYS_CLIENT_ID"),
# client_secret=os.getenv("GENESYS_CLIENT_SECRET")
# )
# token = auth.get_access_token()
Implementation
Step 1: Identify the Target Participant
To initiate a cobrowse session, you must target a specific participant. In Genesys Cloud, cobrowse sessions are typically initiated by an agent toward a customer, or by a system toward an agent.
The API requires the userId of the participant who will be the target of the cobrowse session. If you only have an email address or a phone number, you must first resolve this to a userId.
Here is how to resolve a user ID using the Users API.
Endpoint: GET /api/v2/users
Required Scope: user:read
import requests
def find_user_by_email(auth: GenesysAuth, email: str) -> Optional[str]:
"""
Resolves a Genesys Cloud User ID by email address.
"""
url = f"https://{auth.environment}/api/v2/users"
headers = {
"Authorization": f"Bearer {auth.get_access_token()}",
"Content-Type": "application/json"
}
# Query parameters for filtering
params = {
"email": email,
"pageSize": 10
}
try:
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
users = response.json().get("entities", [])
if not users:
return None
# Return the first matching user ID
return users[0]["id"]
except requests.exceptions.HTTPError as e:
if response.status_code == 404:
return None
raise Exception(f"Error fetching user: {e.response.text}")
# Example
# user_id = find_user_by_email(auth, "customer@example.com")
# if not user_id:
# raise ValueError("User not found in Genesys Cloud.")
Step 2: Initiate the Cobrowse Session
The core action is invoking the POST /api/v2/cobrowse/sessions endpoint. This endpoint creates a new cobrowse session and associates it with the target user.
Critical Parameters:
userId: The ID of the participant to cobrowse with.initiatorId: The ID of the user initiating the session (usually the agent or the application user). If omitted, the system may assign a default or fail depending on configuration.type: The type of cobrowse session. Common values arestandardorremote.
Endpoint: POST /api/v2/cobrowse/sessions
Required Scope: cobrowse:session:write
import requests
import json
def initiate_cobrowse_session(auth: GenesysAuth, target_user_id: str, initiator_user_id: str) -> Dict:
"""
Initiates a new cobrowse session in Genesys Cloud.
Args:
auth: GenesysAuth instance
target_user_id: The ID of the user to cobrowse with
initiator_user_id: The ID of the user initiating the session
Returns:
Dict containing the session details
"""
url = f"https://{auth.environment}/api/v2/cobrowse/sessions"
headers = {
"Authorization": f"Bearer {auth.get_access_token()}",
"Content-Type": "application/json"
}
payload = {
"userId": target_user_id,
"initiatorId": initiator_user_id,
"type": "standard"
}
try:
response = requests.post(url, headers=headers, json=payload)
# Handle common errors
if response.status_code == 401:
raise Exception("Unauthorized. Check your OAuth token and scopes.")
elif response.status_code == 403:
raise Exception("Forbidden. Ensure the client has 'cobrowse:session:write' scope.")
elif response.status_code == 404:
raise Exception(f"User ID {target_user_id} not found or not eligible for cobrowse.")
elif response.status_code == 429:
# Implement retry logic here in production
raise Exception("Rate limit exceeded. Please wait and retry.")
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
raise Exception(f"Failed to initiate cobrowse session: {e.response.text}")
# Example
# session_data = initiate_cobrowse_session(auth, user_id, "agent-user-id-123")
# session_id = session_data["id"]
Expected Response Body:
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"userId": "target-user-id-456",
"initiatorId": "agent-user-id-123",
"type": "standard",
"state": "active",
"createdTimestamp": "2023-10-27T10:00:00.000Z",
"updatedTimestamp": "2023-10-27T10:00:00.000Z",
"links": {
"self": {
"href": "https://mypurecloud.com/api/v2/cobrowse/sessions/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}
}
Step 3: Retrieve the Cobrowse Link for the Client
Once the session is created, you need to provide the target user with a way to join. Genesys Cloud provides a joinUrl or a token that the frontend client uses to initialize the cobrowse SDK.
You can retrieve the session details using the session ID returned in Step 2.
Endpoint: GET /api/v2/cobrowse/sessions/{sessionId}
Required Scope: cobrowse:session:read
def get_cobrowse_join_url(auth: GenesysAuth, session_id: str) -> str:
"""
Retrieves the join URL for a specific cobrowse session.
"""
url = f"https://{auth.environment}/api/v2/cobrowse/sessions/{session_id}"
headers = {
"Authorization": f"Bearer {auth.get_access_token()}",
"Content-Type": "application/json"
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
session_data = response.json()
# The join URL is often embedded in the links or attributes depending on the SDK version
# In many cases, the frontend uses the session ID and a token to join.
# Check for 'joinUrl' or construct it based on documentation.
if "joinUrl" in session_data:
return session_data["joinUrl"]
else:
# Fallback: Return the session ID for the frontend to handle via SDK
return session_data["id"]
except requests.exceptions.HTTPError as e:
raise Exception(f"Failed to get session details: {e.response.text}")
Complete Working Example
This script combines authentication, user resolution, session initiation, and link retrieval into a single workflow.
import os
import time
import requests
from typing import Optional, Dict
# --- Authentication Class (from Step 1) ---
class GenesysAuth:
def __init__(self, client_id: str, client_secret: str, environment: str = "mypurecloud.com"):
self.client_id = client_id
self.client_secret = client_secret
self.environment = environment
self.base_url = f"https://{environment}"
self.token_url = f"{self.base_url}/oauth/token"
self.access_token: Optional[str] = None
self.token_expiry: float = 0
def get_access_token(self) -> str:
if self.access_token and time.time() < (self.token_expiry - 60):
return self.access_token
headers = {"Content-Type": "application/x-www-form-urlencoded"}
data = {
"grant_type": "client_credentials",
"client_id": self.client_id,
"client_secret": self.client_secret
}
try:
response = requests.post(self.token_url, headers=headers, data=data)
response.raise_for_status()
token_data = response.json()
self.access_token = token_data["access_token"]
self.token_expiry = time.time() + token_data["expires_in"]
return self.access_token
except requests.exceptions.HTTPError as e:
raise Exception(f"Authentication failed: {e.response.text}")
# --- Helper Functions ---
def find_user_by_email(auth: GenesysAuth, email: str) -> Optional[str]:
url = f"https://{auth.environment}/api/v2/users"
headers = {"Authorization": f"Bearer {auth.get_access_token()}"}
params = {"email": email, "pageSize": 10}
try:
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
users = response.json().get("entities", [])
return users[0]["id"] if users else None
except requests.exceptions.HTTPError:
return None
def initiate_cobrowse_session(auth: GenesysAuth, target_user_id: str, initiator_user_id: str) -> Dict:
url = f"https://{auth.environment}/api/v2/cobrowse/sessions"
headers = {
"Authorization": f"Bearer {auth.get_access_token()}",
"Content-Type": "application/json"
}
payload = {
"userId": target_user_id,
"initiatorId": initiator_user_id,
"type": "standard"
}
try:
response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
raise Exception(f"Initiation failed: {e.response.text}")
def get_cobrowse_details(auth: GenesysAuth, session_id: str) -> Dict:
url = f"https://{auth.environment}/api/v2/cobrowse/sessions/{session_id}"
headers = {"Authorization": f"Bearer {auth.get_access_token()}"}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
raise Exception(f"Retrieval failed: {e.response.text}")
# --- Main Execution Flow ---
def main():
# Configuration
CLIENT_ID = os.getenv("GENESYS_CLIENT_ID", "your-client-id")
CLIENT_SECRET = os.getenv("GENESYS_CLIENT_SECRET", "your-client-secret")
TARGET_EMAIL = os.getenv("TARGET_USER_EMAIL", "customer@example.com")
INITIATOR_USER_ID = os.getenv("INITIATOR_USER_ID", "your-agent-user-id")
# 1. Authenticate
auth = GenesysAuth(CLIENT_ID, CLIENT_SECRET)
print("Authenticating...")
token = auth.get_access_token()
print(f"Authenticated. Token obtained.")
# 2. Resolve Target User
print(f"Resolving user ID for {TARGET_EMAIL}...")
target_user_id = find_user_by_email(auth, TARGET_EMAIL)
if not target_user_id:
print(f"Error: User with email {TARGET_EMAIL} not found in Genesys Cloud.")
return
print(f"Resolved User ID: {target_user_id}")
# 3. Initiate Cobrowse Session
print("Initiating cobrowse session...")
try:
session_data = initiate_cobrowse_session(auth, target_user_id, INITIATOR_USER_ID)
session_id = session_data["id"]
print(f"Session initiated. ID: {session_id}")
except Exception as e:
print(f"Error initiating session: {e}")
return
# 4. Retrieve Session Details
print("Retrieving session details...")
try:
details = get_cobrowse_details(auth, session_id)
print("Session Details:")
print(f" State: {details.get('state')}")
print(f" Created: {details.get('createdTimestamp')}")
# In a real application, you would send the session_id or join_url to the frontend
# to initialize the Genesys Cloud Cobrowse SDK.
except Exception as e:
print(f"Error retrieving details: {e}")
if __name__ == "__main__":
main()
Common Errors & Debugging
Error: 401 Unauthorized
Cause: The OAuth token is invalid, expired, or missing.
Fix:
- Verify that your
client_idandclient_secretare correct. - Ensure the token has not expired. The
GenesysAuthclass handles refresh, but if you are using raw tokens, check theexpires_infield. - Confirm the token is included in the
Authorization: Bearer <token>header.
Error: 403 Forbidden
Cause: The OAuth client does not have the required scopes.
Fix:
- Go to the Genesys Cloud Admin Console > Platform > Apps.
- Edit your application.
- Ensure
cobrowse:session:writeandcobrowse:session:readare checked under OAuth Scopes. - Save and regenerate the client secret if necessary.
Error: 404 Not Found
Cause: The userId provided does not exist or is not a valid Genesys Cloud user.
Fix:
- Verify the
userIdis correct. - Ensure the user is active in Genesys Cloud.
- If using an email to resolve the user, ensure the email matches exactly with the user’s profile.
Error: 429 Too Many Requests
Cause: You have exceeded the API rate limit.
Fix:
- Implement exponential backoff in your retry logic.
- Cache tokens and session data to reduce API calls.
- Check the
Retry-Afterheader in the response for the recommended wait time.
import time
import random
def retry_with_backoff(func, *args, max_retries=3, **kwargs):
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except requests.exceptions.HTTPError as e:
if e.response.status_code == 429:
wait_time = 2 ** attempt + random.uniform(0, 1)
print(f"Rate limited. Waiting {wait_time:.2f} seconds...")
time.sleep(wait_time)
else:
raise
raise Exception("Max retries exceeded")