Increase Genesys Cloud Data Action Timeouts via the API
What You Will Build
- You will programmatically identify and update the timeout configuration for Genesys Cloud Data Actions that are currently failing due to a 3-second limit.
- You will use the Genesys Cloud Platform APIs to read existing integration configurations and apply a new timeout value via the
patchmethod. - You will use Python with the
requestslibrary to demonstrate the full authentication, read, update, and verification cycle.
Prerequisites
- OAuth Client Type: Machine-to-Machine (M2M) OAuth Client.
- Required Scopes:
integration:read,integration:write,integration:custom. - SDK/API Version: Genesys Cloud API v2.
- Language/Runtime: Python 3.8+ with
requestsinstalled. - Dependencies:
pip install requests
Authentication Setup
Genesys Cloud uses OAuth 2.0 for authentication. For server-side integrations and script-based updates, the Client Credentials grant flow is the standard. You must obtain an access token before making any API calls.
The following function handles the token acquisition. It caches the token to avoid unnecessary re-authentication and handles the 401 error by forcing a refresh.
import requests
import json
import time
from typing import Optional
GENESYS_DOMAIN = "api.mypurecloud.com" # Replace with your specific region domain
CLIENT_ID = "your_client_id"
CLIENT_SECRET = "your_client_secret"
def get_access_token() -> str:
"""
Retrieves an OAuth 2.0 access token from Genesys Cloud.
Returns:
str: The access token.
Raises:
Exception: If authentication fails.
"""
url = f"https://{GENESYS_DOMAIN}/oauth/token"
payload = {
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"scope": "integration:read integration:write integration:custom"
}
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
response = requests.post(url, data=payload, headers=headers)
if response.status_code != 200:
raise Exception(f"Authentication failed with status {response.status_code}: {response.text}")
token_data = response.json()
return token_data["access_token"]
def get_authenticated_headers(token: Optional[str] = None) -> dict:
"""
Returns the headers required for API requests, including the Authorization Bearer token.
"""
if not token:
token = get_access_token()
return {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
Implementation
Step 1: Locate the Data Action Integration
Data Actions in Genesys Cloud are exposed as Integrations. To update a timeout, you must first identify the specific Integration ID associated with the Data Action causing the latency issues. You cannot update an integration by name; you must use its UUID.
The following code queries the list of integrations and filters for Data Actions. Note that Data Actions typically have the type data_action or are custom integrations linked to data action definitions.
def find_data_action_integration(token: str, action_name: str) -> Optional[dict]:
"""
Searches for a specific Data Action integration by name.
Args:
token (str): OAuth access token.
action_name (str): The display name of the Data Action.
Returns:
dict: The integration object if found, None otherwise.
"""
url = f"https://{GENESYS_DOMAIN}/api/v2/integrations"
headers = get_authenticated_headers(token)
# Pagination handling
page_size = 25
page_number = 1
all_integrations = []
while True:
params = {
"pageSize": page_size,
"pageNumber": page_number,
"type": "custom" # Data actions often fall under custom or specific types
}
response = requests.get(url, headers=headers, params=params)
if response.status_code == 429:
# Rate limit handling
retry_after = int(response.headers.get("Retry-After", 2))
print(f"Rate limited. Waiting {retry_after} seconds...")
time.sleep(retry_after)
continue
if response.status_code != 200:
raise Exception(f"Failed to fetch integrations: {response.status_code} - {response.text}")
data = response.json()
all_integrations.extend(data["entities"])
if len(data["entities"]) < page_size:
break
page_number += 1
# Filter for the specific action
# Note: The exact field depends on how the action was created.
# Often, the 'name' field matches the Data Action display name.
for integration in all_integrations:
if integration.get("name") == action_name:
return integration
return None
Step 2: Inspect Current Configuration
Before modifying the integration, you must retrieve its current configuration. The timeout setting is not always a top-level field in the integration summary. It is often nested within the configuration object or specific to the endpoint definition.
For Data Actions, the timeout is frequently defined in the configuration block under a key like timeout or httpTimeout. If the field is missing, Genesys Cloud defaults to 3 seconds (3000 ms).
def get_integration_details(token: str, integration_id: str) -> dict:
"""
Retrieves the full configuration of a specific integration.
Args:
token (str): OAuth access token.
integration_id (str): The UUID of the integration.
Returns:
dict: The full integration object.
"""
url = f"https://{GENESYS_DOMAIN}/api/v2/integrations/{integration_id}"
headers = get_authenticated_headers(token)
response = requests.get(url, headers=headers)
if response.status_code == 404:
raise Exception(f"Integration {integration_id} not found.")
elif response.status_code != 200:
raise Exception(f"Failed to fetch integration details: {response.status_code} - {response.text}")
return response.json()
Step 3: Update the Timeout Value
The Genesys Cloud API uses HTTP PATCH for partial updates. You must send a JSON payload containing only the fields you wish to change.
For Data Actions, the timeout is typically specified in milliseconds. To increase the limit from 3 seconds to 5 seconds, you set the value to 5000. Some integrations may require the timeout to be set in the configuration map directly.
Critical Note: The exact key for the timeout varies by integration type. For standard HTTP-based Data Actions, it is often httpTimeout or timeout within the configuration object. If the configuration object does not exist, you must create it.
def update_integration_timeout(token: str, integration_id: str, new_timeout_ms: int) -> bool:
"""
Updates the timeout setting for a specific integration.
Args:
token (str): OAuth access token.
integration_id (str): The UUID of the integration.
new_timeout_ms (int): The new timeout value in milliseconds (e.g., 5000).
Returns:
bool: True if the update was successful.
"""
url = f"https://{GENESYS_DOMAIN}/api/v2/integrations/{integration_id}"
headers = get_authenticated_headers(token)
# First, get the current config to preserve other settings
current_config = get_integration_details(token, integration_id)
# Ensure the configuration object exists
if "configuration" not in current_config:
current_config["configuration"] = {}
# Update the timeout field
# Note: Verify the exact key for your specific Data Action type.
# 'httpTimeout' is common for custom HTTP integrations.
current_config["configuration"]["httpTimeout"] = new_timeout_ms
# Prepare the patch payload
# We only send the configuration block to avoid overwriting other fields
patch_payload = {
"configuration": current_config["configuration"]
}
response = requests.patch(
url,
headers=headers,
data=json.dumps(patch_payload)
)
if response.status_code == 200:
print(f"Successfully updated timeout for integration {integration_id} to {new_timeout_ms}ms")
return True
elif response.status_code == 400:
print(f"Bad Request: {response.text}")
# Common error: Invalid timeout value or unsupported key
return False
elif response.status_code == 403:
print(f"Forbidden: Check if your OAuth client has integration:write scope")
return False
else:
raise Exception(f"Update failed with status {response.status_code}: {response.text}")
Complete Working Example
This script combines the previous steps into a single executable flow. It authenticates, finds a Data Action by name, updates its timeout to 5 seconds, and verifies the change.
import requests
import json
import time
import sys
from typing import Optional
# Configuration
GENESYS_DOMAIN = "api.mypurecloud.com" # Update this
CLIENT_ID = "your_client_id"
CLIENT_SECRET = "your_client_secret"
TARGET_ACTION_NAME = "Slow_External_API_Call" # The name of your Data Action
NEW_TIMEOUT_MS = 5000 # 5 seconds
def get_access_token() -> str:
url = f"https://{GENESYS_DOMAIN}/oauth/token"
payload = {
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"scope": "integration:read integration:write integration:custom"
}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(url, data=payload, headers=headers)
if response.status_code != 200:
raise Exception(f"Auth failed: {response.text}")
return response.json()["access_token"]
def get_headers(token: str) -> dict:
return {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
def find_integration_by_name(token: str, name: str) -> Optional[str]:
url = f"https://{GENESYS_DOMAIN}/api/v2/integrations"
headers = get_headers(token)
page = 1
while True:
params = {"pageSize": 25, "pageNumber": page}
resp = requests.get(url, headers=headers, params=params)
if resp.status_code == 429:
time.sleep(int(resp.headers.get("Retry-After", 2)))
continue
if resp.status_code != 200:
raise Exception(f"Error fetching integrations: {resp.text}")
data = resp.json()
for entity in data["entities"]:
if entity.get("name") == name:
return entity["id"]
if len(data["entities"]) < 25:
break
page += 1
return None
def update_timeout(token: str, integration_id: str, timeout_ms: int):
url = f"https://{GENESYS_DOMAIN}/api/v2/integrations/{integration_id}"
headers = get_headers(token)
# Get current config
get_resp = requests.get(url, headers=headers)
if get_resp.status_code != 200:
raise Exception(f"Could not fetch integration details: {get_resp.text}")
current = get_resp.json()
# Prepare configuration update
if "configuration" not in current:
current["configuration"] = {}
# Update timeout
current["configuration"]["httpTimeout"] = timeout_ms
# Patch
patch_data = {"configuration": current["configuration"]}
patch_resp = requests.patch(url, headers=headers, data=json.dumps(patch_data))
if patch_resp.status_code == 200:
print(f"Success: Timeout updated to {timeout_ms}ms")
else:
print(f"Error: {patch_resp.status_code} - {patch_resp.text}")
# Debug: Print the exact error body
print(f"Response Body: {patch_resp.text}")
def main():
try:
print("1. Authenticating...")
token = get_access_token()
print(f"2. Finding integration '{TARGET_ACTION_NAME}'...")
integration_id = find_integration_by_name(token, TARGET_ACTION_NAME)
if not integration_id:
print(f"Error: Integration '{TARGET_ACTION_NAME}' not found.")
sys.exit(1)
print(f"3. Found integration ID: {integration_id}")
print(f"4. Updating timeout to {NEW_TIMEOUT_MS}ms...")
update_timeout(token, integration_id, NEW_TIMEOUT_MS)
except Exception as e:
print(f"Fatal Error: {e}")
sys.exit(1)
if __name__ == "__main__":
main()
Common Errors & Debugging
Error: 400 Bad Request - “Invalid configuration”
Cause: The key used for the timeout is incorrect for the specific integration type. While httpTimeout is common, some legacy integrations or specific third-party connectors may use timeout, requestTimeout, or require the value in seconds rather than milliseconds.
Fix: Inspect the existing configuration object of a working integration with a known timeout. Use get_integration_details to print the current JSON structure. Look for existing timeout keys. If you are unsure, check the documentation for the specific integration type.
# Debug snippet to inspect current configuration
current = get_integration_details(token, integration_id)
print(json.dumps(current.get("configuration", {}), indent=2))
Error: 403 Forbidden
Cause: The OAuth client lacks the integration:write or integration:custom scope.
Fix: Go to the Genesys Cloud Admin console → Security → OAuth Clients. Select your client and ensure the required scopes are checked. Regenerate the client secret if necessary.
Error: 429 Too Many Requests
Cause: You are exceeding the rate limit for the integrations endpoint.
Fix: Implement exponential backoff. The response header Retry-After indicates the number of seconds to wait.
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 5))
time.sleep(retry_after)
# Retry the request
Error: Timeout Still Fails at 3 Seconds
Cause: The Data Action is configured to use a global default or the timeout setting is overridden by the underlying HTTP client in the Genesys Cloud platform for that specific connector type. Some Data Actions do not support dynamic timeout updates via the API and require a platform-wide adjustment or a different connector type.
Fix: Verify if the integration type supports httpTimeout. If not, you may need to refactor the Data Action to use a “Custom” integration type which offers more granular control over HTTP settings, including timeouts, retries, and headers.