Choosing Between Conversations API and Analytics API for Real-Time vs Historical Data
What You Will Build
- You will build a Python script that retrieves active conversation details using the Conversations API and historical conversation metrics using the Analytics API.
- This tutorial uses the Genesys Cloud PureCloud Platform Client V2 SDK and raw HTTP requests for clarity.
- The programming language covered is Python 3.9+.
Prerequisites
- OAuth Client Type: Public or Confidential client with appropriate scopes.
- Required Scopes:
conversation:readfor accessing active conversations.analytics:conversation:readfor accessing historical analytics data.
- SDK Version:
genesyscloud-py-client>= 1.0.0. - Language/Runtime: Python 3.9 or later.
- External Dependencies:
genesyscloud-py-clientrequestspython-dotenv(for secure credential management)
Authentication Setup
Genesys Cloud uses OAuth 2.0 for authentication. You must obtain an access token before making any API calls. For production applications, implement token caching and automatic refresh. For this tutorial, we will use the SDK’s built-in authentication helper which handles token retrieval and storage.
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
GENESYS_CLOUD_ENVIRONMENT=us-east-1
Install the required packages:
pip install genesyscloud-py-client requests python-dotenv
Initialize the SDK in your Python script:
import os
from dotenv import load_dotenv
from purecloudplatformclientv2 import ApiClient, Configuration, Environment
from purecloudplatformclientv2.rest import ApiException
load_dotenv()
def get_purecloud_client():
"""
Initializes the PureCloud API client using environment variables.
"""
try:
# Load environment variables
client_id = os.getenv("GENESYS_CLOUD_CLIENT_ID")
client_secret = os.getenv("GENESYS_CLOUD_CLIENT_SECRET")
environment = os.getenv("GENESYS_CLOUD_ENVIRONMENT", "us-east-1")
# Configure the client
configuration = Configuration()
configuration.host = Environment.get_host(environment)
# Initialize API client with OAuth2 client credentials flow
api_client = ApiClient(configuration=configuration)
api_client.configuration.access_token = api_client.authenticator.get_access_token(
client_id=client_id,
client_secret=client_secret
)
return api_client
except Exception as e:
print(f"Failed to initialize PureCloud client: {e}")
raise
# Get the authenticated client
api_client = get_purecloud_client()
Implementation
Step 1: Understanding the Conversations API (/api/v2/conversations)
The Conversations API provides real-time access to currently active conversations. It is designed for operational purposes, such as:
- Monitoring live interactions.
- Providing agent assist features.
- Updating conversation metadata during an interaction.
- Retrieving participant details for active sessions.
This API does not store historical data. Once a conversation ends, it is no longer accessible via this endpoint. The data is transient and exists only while the conversation is active.
Use Case: Retrieve Active Conversations for a Specific User
We will retrieve all active conversations for a specific user (e.g., an agent).
from purecloudplatformclientv2 import ConversationApi
def get_active_conversations_for_user(user_id: str, api_client: ApiClient) -> list:
"""
Retrieves all active conversations for a specific user.
Args:
user_id: The ID of the user whose active conversations to retrieve.
api_client: The initialized PureCloud API client.
Returns:
A list of active conversation objects.
"""
conversation_api = ConversationApi(api_client)
try:
# Get active conversations for the user
response = conversation_api.get_conversations_user_conversations(
user_id=user_id,
expand=["participants", "wraps"] # Expand related entities
)
return response.entities if response.entities else []
except ApiException as e:
if e.status == 401:
print("Authentication failed. Check your OAuth token.")
elif e.status == 403:
print("Forbidden. Ensure your client has 'conversation:read' scope.")
elif e.status == 404:
print(f"User {user_id} not found.")
else:
print(f"API Error {e.status}: {e.body}")
raise
# Example usage
USER_ID = "your_user_id_here"
active_conversations = get_active_conversations_for_user(USER_ID, api_client)
for conv in active_conversations:
print(f"Active Conversation ID: {conv.id}")
print(f" Type: {conv.type}")
print(f" State: {conv.state}")
print(f" Created: {conv.created_time}")
if conv.participants:
for participant in conv.participants:
print(f" Participant: {participant.user.name} ({participant.role})")
print("-" * 50)
Expected Response Structure (JSON):
{
"entities": [
{
"id": "conv-12345678-1234-1234-1234-123456789012",
"type": "voice",
"state": "connected",
"created_time": "2023-10-27T10:30:00.000Z",
"participants": [
{
"user": {
"id": "user-123",
"name": "Agent Smith"
},
"role": "agent"
},
{
"external_contact": {
"phone_number": "+15551234567"
},
"role": "customer"
}
]
}
],
"page_count": 1,
"page_size": 25
}
Error Handling:
- 401 Unauthorized: Your OAuth token is expired or invalid. Refresh the token.
- 403 Forbidden: Your OAuth client lacks the
conversation:readscope. - 404 Not Found: The specified
user_iddoes not exist.
Step 2: Understanding the Analytics API (/api/v2/analytics/conversations)
The Analytics API provides historical data about conversations. It is designed for reporting, business intelligence, and post-interaction analysis. This API queries the data warehouse, which has a slight delay (typically 15-30 minutes) compared to real-time data.
This API supports:
- Aggregated metrics (e.g., average handle time, total conversations).
- Detailed conversation records with full metadata.
- Time-range filtering (e.g., last 7 days, last month).
- Complex filtering by queue, skill, user, or custom attributes.
Use Case: Retrieve Historical Conversation Details for the Last 7 Days
We will retrieve detailed conversation records for the last 7 days.
from purecloudplatformclientv2 import ConversationAnalyticsApi
from datetime import datetime, timedelta
from purecloudplatformclientv2.models import ConversationQueryRequest
def get_historical_conversations(api_client: ApiClient, days_back: int = 7) -> list:
"""
Retrieves historical conversation details for the specified number of days.
Args:
api_client: The initialized PureCloud API client.
days_back: Number of days to look back for conversation data.
Returns:
A list of historical conversation objects.
"""
conversation_analytics_api = ConversationAnalyticsApi(api_client)
# Define the time range
end_time = datetime.utcnow()
start_time = end_time - timedelta(days=days_back)
# Format times as ISO 8601 strings
start_time_str = start_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
end_time_str = end_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
# Build the query request
query_request = ConversationQueryRequest(
date_from=start_time_str,
date_to=end_time_str,
size=25, # Page size
sort_by="created_time",
sort_order="desc"
)
try:
# Execute the query
response = conversation_analytics_api.post_analytics_conversations_details_query(
body=query_request
)
return response.entities if response.entities else []
except ApiException as e:
if e.status == 401:
print("Authentication failed. Check your OAuth token.")
elif e.status == 403:
print("Forbidden. Ensure your client has 'analytics:conversation:read' scope.")
elif e.status == 422:
print("Unprocessable Entity. Check your query parameters.")
else:
print(f"API Error {e.status}: {e.body}")
raise
# Example usage
historical_conversations = get_historical_conversations(api_client, days_back=7)
for conv in historical_conversations:
print(f"Historical Conversation ID: {conv.id}")
print(f" Type: {conv.type}")
print(f" Created: {conv.created_time}")
print(f" Duration: {conv.duration_seconds} seconds")
if conv.queue:
print(f" Queue: {conv.queue.name}")
if conv.agents:
for agent in conv.agents:
print(f" Agent: {agent.user.name}")
print("-" * 50)
Expected Response Structure (JSON):
{
"page_count": 1,
"page_size": 25,
"entities": [
{
"id": "conv-87654321-4321-4321-4321-210987654321",
"type": "voice",
"created_time": "2023-10-26T15:45:00.000Z",
"duration_seconds": 120.5,
"queue": {
"id": "queue-123",
"name": "Support Team"
},
"agents": [
{
"user": {
"id": "user-456",
"name": "Agent Doe"
}
}
],
"wrap_up_code": "Resolved",
"hold_time_seconds": 10.2,
"talk_time_seconds": 110.3
}
]
}
Error Handling:
- 401 Unauthorized: Your OAuth token is expired or invalid.
- 403 Forbidden: Your OAuth client lacks the
analytics:conversation:readscope. - 422 Unprocessable Entity: Your query parameters are invalid (e.g., invalid date format, missing required fields).
- 429 Too Many Requests: You have exceeded the rate limit. Implement exponential backoff.
Step 3: Processing Results and Pagination
Both APIs support pagination. The Conversations API returns a page_count and page_size, but for active conversations, the result set is usually small. The Analytics API can return large datasets, so pagination is critical.
Handling Pagination for Analytics API
from purecloudplatformclientv2.models import ConversationQueryRequest
def get_all_historical_conversations(api_client: ApiClient, days_back: int = 7) -> list:
"""
Retrieves all historical conversation details with pagination handling.
Args:
api_client: The initialized PureCloud API client.
days_back: Number of days to look back for conversation data.
Returns:
A list of all historical conversation objects.
"""
conversation_analytics_api = ConversationAnalyticsApi(api_client)
end_time = datetime.utcnow()
start_time = end_time - timedelta(days=days_back)
start_time_str = start_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
end_time_str = end_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
all_conversations = []
page_number = 1
while True:
query_request = ConversationQueryRequest(
date_from=start_time_str,
date_to=end_time_str,
page=page_number,
size=100, # Max page size is 250, but 100 is safer for stability
sort_by="created_time",
sort_order="desc"
)
try:
response = conversation_analytics_api.post_analytics_conversations_details_query(
body=query_request
)
if not response.entities:
break
all_conversations.extend(response.entities)
# Check if there are more pages
if page_number >= response.page_count:
break
page_number += 1
except ApiException as e:
print(f"API Error on page {page_number}: {e.status} - {e.body}")
break
return all_conversations
# Example usage
all_historical_conversations = get_all_historical_conversations(api_client, days_back=30)
print(f"Total conversations retrieved: {len(all_historical_conversations)}")
Complete Working Example
Below is a complete, runnable Python script that demonstrates both APIs.
import os
from dotenv import load_dotenv
from purecloudplatformclientv2 import ApiClient, Configuration, Environment, ConversationApi, ConversationAnalyticsApi
from purecloudplatformclientv2.rest import ApiException
from purecloudplatformclientv2.models import ConversationQueryRequest
from datetime import datetime, timedelta
import json
load_dotenv()
def get_purecloud_client():
"""Initializes the PureCloud API client."""
try:
client_id = os.getenv("GENESYS_CLOUD_CLIENT_ID")
client_secret = os.getenv("GENESYS_CLOUD_CLIENT_SECRET")
environment = os.getenv("GENESYS_CLOUD_ENVIRONMENT", "us-east-1")
configuration = Configuration()
configuration.host = Environment.get_host(environment)
api_client = ApiClient(configuration=configuration)
api_client.configuration.access_token = api_client.authenticator.get_access_token(
client_id=client_id,
client_secret=client_secret
)
return api_client
except Exception as e:
print(f"Failed to initialize PureCloud client: {e}")
raise
def get_active_conversations(user_id: str, api_client: ApiClient) -> list:
"""Retrieves active conversations for a user."""
conversation_api = ConversationApi(api_client)
try:
response = conversation_api.get_conversations_user_conversations(
user_id=user_id,
expand=["participants"]
)
return response.entities if response.entities else []
except ApiException as e:
print(f"Error fetching active conversations: {e.status} - {e.body}")
return []
def get_historical_conversations(api_client: ApiClient, days_back: int = 7) -> list:
"""Retrieves historical conversations for the last N days."""
conversation_analytics_api = ConversationAnalyticsApi(api_client)
end_time = datetime.utcnow()
start_time = end_time - timedelta(days=days_back)
query_request = ConversationQueryRequest(
date_from=start_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
date_to=end_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
size=25,
sort_by="created_time",
sort_order="desc"
)
try:
response = conversation_analytics_api.post_analytics_conversations_details_query(
body=query_request
)
return response.entities if response.entities else []
except ApiException as e:
print(f"Error fetching historical conversations: {e.status} - {e.body}")
return []
def main():
# Initialize client
api_client = get_purecloud_client()
# Define user ID for active conversations
USER_ID = "your_user_id_here"
# Fetch active conversations
print("Fetching Active Conversations...")
active_convs = get_active_conversations(USER_ID, api_client)
if active_convs:
print(f"Found {len(active_convs)} active conversation(s).")
for conv in active_convs:
print(json.dumps({
"id": conv.id,
"type": conv.type,
"state": conv.state,
"created_time": conv.created_time.isoformat()
}, indent=2))
else:
print("No active conversations found.")
print("\n" + "="*50 + "\n")
# Fetch historical conversations
print("Fetching Historical Conversations (Last 7 Days)...")
historical_convs = get_historical_conversations(api_client, days_back=7)
if historical_convs:
print(f"Found {len(historical_convs)} historical conversation(s).")
for conv in historical_convs:
print(json.dumps({
"id": conv.id,
"type": conv.type,
"created_time": conv.created_time.isoformat(),
"duration_seconds": conv.duration_seconds,
"queue_name": conv.queue.name if conv.queue else None
}, indent=2))
else:
print("No historical conversations found.")
if __name__ == "__main__":
main()
Common Errors & Debugging
Error: 401 Unauthorized
Cause: The OAuth access token is expired, invalid, or missing.
Fix: Ensure your get_purecloud_client function correctly retrieves a new token. The SDK’s get_access_token method handles this, but if you are managing tokens manually, implement a refresh flow.
# If managing tokens manually
if api_client.configuration.access_token_expired:
api_client.configuration.access_token = api_client.authenticator.get_access_token(
client_id=client_id,
client_secret=client_secret
)
Error: 403 Forbidden
Cause: The OAuth client lacks the required scope.
Fix:
- For
/api/v2/conversations, ensure the client hasconversation:read. - For
/api/v2/analytics/conversations, ensure the client hasanalytics:conversation:read.
Check the client’s scopes in the Genesys Cloud Admin portal under Administration > Security > OAuth Clients.
Error: 422 Unprocessable Entity
Cause: Invalid query parameters in the Analytics API request.
Fix: Verify that date_from and date_to are valid ISO 8601 strings. Ensure the time range does not exceed the maximum allowed range (typically 90 days for detailed queries).
# Validate dates
if (end_time - start_time).days > 90:
raise ValueError("Date range exceeds maximum allowed limit of 90 days.")
Error: 429 Too Many Requests
Cause: You have exceeded the API rate limit.
Fix: Implement exponential backoff. Do not retry immediately. Wait for a period that increases with each retry (e.g., 1s, 2s, 4s, 8s).
import time
import requests
def make_request_with_retry(url: str, headers: dict, max_retries: int = 3) -> requests.Response:
"""Makes an HTTP request with exponential backoff for 429 errors."""
for attempt in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code == 429:
wait_time = 2 ** attempt
print(f"Rate limited. Waiting {wait_time} seconds...")
time.sleep(wait_time)
else:
return response
raise Exception("Max retries exceeded for 429 error.")