How to Increase Genesys Cloud Data Action Timeout Limits
What You Will Build
- This tutorial provides the exact API calls required to identify and modify the timeout configuration for Data Actions in Genesys Cloud CX.
- This uses the Genesys Cloud Platform API v2 endpoints for Integrations and Data Actions, specifically the
PUT /api/v2/integrations/dataactions/{dataActionId}endpoint. - This covers Python and cURL implementations to demonstrate both SDK abstraction and raw HTTP control.
Prerequisites
- OAuth Client Type: Service Account or Client Credentials Grant.
- Required Scopes:
dataactions:write,dataactions:read,integrations:write,integrations:read. - API Version: Genesys Cloud Platform API v2.
- Language/Runtime: Python 3.8+ with
requestslibrary, or a standard terminal withcurl. - Dependencies:
pip install requests
Authentication Setup
Before modifying any configuration, you must obtain a valid access token. The Data Action endpoints require authenticated sessions with specific write permissions. The following Python script demonstrates the standard Client Credentials flow, which is the recommended method for server-to-server integrations and administrative scripts.
import requests
import json
import time
# Configuration
CLIENT_ID = "your_client_id"
CLIENT_SECRET = "your_client_secret"
ENVIRONMENT = "mypurecloud.com" # Change to your specific environment (e.g., usw2.pure.cloud)
def get_access_token():
"""
Authenticates with Genesys Cloud using Client Credentials flow.
Returns the access token string.
"""
url = f"https://login.{ENVIRONMENT}/oauth/token"
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
data = {
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
}
try:
response = requests.post(url, headers=headers, data=data)
response.raise_for_status()
token_data = response.json()
return token_data.get("access_token")
except requests.exceptions.HTTPError as e:
print(f"Authentication failed: {e.response.status_code}")
print(e.response.text)
raise
except requests.exceptions.RequestException as e:
print(f"Network error during authentication: {e}")
raise
# Execute authentication
access_token = get_access_token()
print(f"Token acquired successfully.")
Implementation
Step 1: Locate the Data Action ID
You cannot update a Data Action without its unique identifier. Data Actions are often nested under Integrations or managed directly via the dataactions namespace. The most reliable method to find a specific Data Action by name is to query the list of all Data Actions and filter client-side, or use the search endpoint if available for your specific integration type.
The following code retrieves all Data Actions associated with your organization.
import requests
def list_data_actions(access_token):
"""
Retrieves the list of all Data Actions.
Requires scope: dataactions:read
"""
url = f"https://api.{ENVIRONMENT}/api/v2/integrations/dataactions"
headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/json",
"Content-Type": "application/json"
}
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
data_actions = response.json().get("entities", [])
return data_actions
except requests.exceptions.HTTPError as e:
print(f"Failed to retrieve Data Actions: {e.response.status_code}")
print(e.response.text)
return []
# Fetch and print available actions
data_actions = list_data_actions(access_token)
# Filter for a specific action name (example: "MySlowAPIAction")
target_name = "MySlowAPIAction"
target_action = next((action for action in data_actions if action.get("name") == target_name), None)
if target_action:
print(f"Found Data Action: {target_action['name']} (ID: {target_action['id']})")
print(f"Current Timeout: {target_action.get('timeout', 'Not set')} ms")
else:
print(f"Data Action '{target_name}' not found.")
target_action = None
Step 2: Analyze the Current Configuration
The “3 seconds” limit you are experiencing is likely defined in the timeout field of the Data Action entity. In Genesys Cloud, this value is specified in milliseconds. Therefore, 3 seconds equals 3000 ms.
If the field is missing or set to 3000, and your downstream API takes 5 seconds (5000 ms), the Genesys Cloud engine will terminate the request, returning a timeout error to the Flow or Application.
Examine the JSON structure of the retrieved action:
{
"id": "12345-67890-abcde",
"name": "MySlowAPIAction",
"description": "Fetches user data from external CRM",
"type": "http",
"timeout": 3000,
"configuration": {
"method": "GET",
"url": "https://api.external-crm.com/users/{userId}"
},
"createdTime": "2023-01-01T00:00:00.000Z",
"updatedTime": "2023-01-01T00:00:00.000Z"
}
Critical Note: The maximum allowed timeout for standard Data Actions is typically 30,000 ms (30 seconds). If you attempt to set this value higher than the platform limit, the API will return a 400 Bad Request error. If your integration genuinely requires more than 30 seconds, you must re-architect the solution to use asynchronous patterns (e.g., Webhooks or Polling) rather than a synchronous Data Action.
Step 3: Update the Timeout Value
To increase the limit to handle 5-second calls, you must set the timeout field to at least 5000 (5 seconds). It is best practice to add a buffer. We will set it to 10000 (10 seconds) to accommodate network latency and occasional spikes.
This operation uses the PUT method to replace the entire entity. You must include all required fields in the request body.
def update_data_action_timeout(access_token, action_id, new_timeout_ms=10000):
"""
Updates the timeout for a specific Data Action.
Requires scope: dataactions:write
"""
url = f"https://api.{ENVIRONMENT}/api/v2/integrations/dataactions/{action_id}"
headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/json",
"Content-Type": "application/json"
}
# First, retrieve the current full entity to ensure no fields are lost during PUT
# This is a safe pattern for partial updates in REST APIs that use PUT
current_action = requests.get(url, headers=headers).json()
# Modify the timeout
current_action["timeout"] = new_timeout_ms
# Optional: Log the change
print(f"Updating timeout for '{current_action['name']}' to {new_timeout_ms} ms")
try:
response = requests.put(url, headers=headers, json=current_action)
response.raise_for_status()
updated_action = response.json()
print(f"Successfully updated timeout to: {updated_action.get('timeout')} ms")
return updated_action
except requests.exceptions.HTTPError as e:
print(f"Update failed: {e.response.status_code}")
print(f"Error Details: {e.response.text}")
raise
# Execute the update if the target was found
if target_action:
try:
update_data_action_timeout(access_token, target_action["id"], new_timeout_ms=10000)
except Exception as e:
print(f"Failed to update action: {e}")
Step 4: Verify the Change
After the update, verify that the new timeout is persisted. This step ensures that the API accepted the change and that there are no eventual consistency delays (though Genesys Cloud APIs are generally strongly consistent for writes).
def verify_timeout(access_token, action_id):
"""
Verifies the new timeout value is persisted.
"""
url = f"https://api.{ENVIRONMENT}/api/v2/integrations/dataactions/{action_id}"
headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/json"
}
response = requests.get(url, headers=headers)
response.raise_for_status()
action = response.json()
print(f"Verification: Current timeout is {action.get('timeout')} ms")
return action.get("timeout")
if target_action:
verify_timeout(access_token, target_action["id"])
Complete Working Example
The following script combines authentication, discovery, and update logic into a single executable module. It includes error handling for common scenarios such as missing permissions or non-existent actions.
#!/usr/bin/env python3
"""
Genesys Cloud Data Action Timeout Updater
This script authenticates to Genesys Cloud, finds a Data Action by name,
and updates its timeout value to prevent premature termination of long-running
API calls.
Usage:
python update_data_action_timeout.py
"""
import os
import sys
import requests
# --- Configuration ---
CLIENT_ID = os.getenv("GENESYS_CLIENT_ID", "your_client_id")
CLIENT_SECRET = os.getenv("GENESYS_CLIENT_SECRET", "your_client_secret")
ENVIRONMENT = os.getenv("GENESYS_ENVIRONMENT", "mypurecloud.com")
TARGET_ACTION_NAME = os.getenv("TARGET_ACTION_NAME", "MySlowAPIAction")
NEW_TIMEOUT_MS = int(os.getenv("NEW_TIMEOUT_MS", "10000")) # 10 seconds
# --- Constants ---
AUTH_URL = f"https://login.{ENVIRONMENT}/oauth/token"
API_BASE_URL = f"https://api.{ENVIRONMENT}/api/v2"
def log(message, level="INFO"):
print(f"[{level}] {message}")
def authenticate():
"""Obtains an OAuth access token."""
log("Authenticating with Genesys Cloud...")
headers = {"Content-Type": "application/x-www-form-urlencoded"}
data = {
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
}
try:
response = requests.post(AUTH_URL, headers=headers, data=data, timeout=10)
response.raise_for_status()
token = response.json().get("access_token")
if not token:
raise ValueError("No access_token in response")
log("Authentication successful.")
return token
except requests.exceptions.HTTPError as e:
log(f"Authentication failed: {e.response.status_code} - {e.response.text}", "ERROR")
sys.exit(1)
except Exception as e:
log(f"Unexpected error during authentication: {e}", "ERROR")
sys.exit(1)
def find_data_action(access_token, name):
"""Searches for a Data Action by name."""
log(f"Searching for Data Action: {name}")
url = f"{API_BASE_URL}/integrations/dataactions"
headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/json"
}
try:
response = requests.get(url, headers=headers, timeout=15)
response.raise_for_status()
entities = response.json().get("entities", [])
# Filter for exact name match
match = next((entity for entity in entities if entity.get("name") == name), None)
if match:
log(f"Found Data Action ID: {match['id']}")
return match
else:
log(f"Data Action '{name}' not found. Check spelling and permissions.", "WARNING")
return None
except requests.exceptions.HTTPError as e:
log(f"Failed to list Data Actions: {e.response.status_code}", "ERROR")
return None
except Exception as e:
log(f"Error fetching Data Actions: {e}", "ERROR")
return None
def update_timeout(access_token, action_id, current_action, new_timeout):
"""Updates the timeout field of the Data Action."""
log(f"Updating timeout for {current_action['name']} to {new_timeout} ms")
url = f"{API_BASE_URL}/integrations/dataactions/{action_id}"
headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/json",
"Content-Type": "application/json"
}
# Prepare the payload with the updated timeout
payload = current_action.copy()
payload["timeout"] = new_timeout
try:
response = requests.put(url, headers=headers, json=payload, timeout=15)
response.raise_for_status()
log("Update successful.")
return True
except requests.exceptions.HTTPError as e:
log(f"Update failed: {e.response.status_code} - {e.response.text}", "ERROR")
# Specific handling for common errors
if e.response.status_code == 400:
log("Bad Request: Ensure the timeout value is within platform limits (typically max 30000 ms).", "ERROR")
elif e.response.status_code == 403:
log("Forbidden: Ensure the client has 'dataactions:write' scope.", "ERROR")
return False
except Exception as e:
log(f"Unexpected error during update: {e}", "ERROR")
return False
def main():
# 1. Authenticate
access_token = authenticate()
# 2. Find the Action
action = find_data_action(access_token, TARGET_ACTION_NAME)
if not action:
log("Aborting: Could not locate the target Data Action.", "ERROR")
sys.exit(1)
# 3. Check current state
current_timeout = action.get("timeout", 0)
if current_timeout == NEW_TIMEOUT_MS:
log(f"Timeout is already set to {NEW_TIMEOUT_MS} ms. No action needed.")
return
# 4. Update the Timeout
success = update_timeout(access_token, action["id"], action, NEW_TIMEOUT_MS)
if success:
log(f"Successfully updated timeout to {NEW_TIMEOUT_MS} ms.")
else:
log("Failed to update timeout. Check logs for details.", "ERROR")
sys.exit(1)
if __name__ == "__main__":
main()
Common Errors & Debugging
Error: 403 Forbidden
What causes it: The OAuth client used in the authentication step does not have the required scope dataactions:write. Read-only scopes (dataactions:read) allow you to view the configuration but not modify it.
How to fix it:
- Navigate to the Genesys Cloud Admin Console.
- Go to Organization > Security > OAuth Clients.
- Select your Client ID.
- In the Scopes tab, search for
dataactions. - Ensure
dataactions:writeis checked. - Save the changes. Note that you may need to re-authenticate to get a new token with the updated scopes.
Error: 400 Bad Request - “Timeout exceeds maximum allowed value”
What causes it: You attempted to set the timeout field to a value higher than the platform’s hard limit. For synchronous Data Actions, this limit is typically 30,000 milliseconds (30 seconds).
How to fix it:
- Reduce the
NEW_TIMEOUT_MSvariable in your script to30000or lower. - If your downstream API genuinely requires more than 30 seconds, you cannot use a synchronous Data Action. You must refactor your Genesys Cloud Flow to use a Webhook trigger or a Polling pattern with a separate API call that checks for completion status.
Error: 404 Not Found
What causes it: The Data Action ID or Name does not exist in the current organization or environment. This often happens when developers test in mypurecloud.com (Sandbox) but target an ID from usw2.pure.cloud (Production).
How to fix it:
- Verify the
ENVIRONMENTvariable matches the Genesys Cloud environment where the Data Action was created. - Run the
find_data_actionfunction logic manually to list all available actions and confirm the name spelling is exact (case-sensitive).
Error: 429 Too Many Requests
What causes it: Your application has exceeded the rate limit for the dataactions API endpoints. Genesys Cloud enforces strict rate limits to protect platform stability.
How to fix it:
- Implement exponential backoff in your retry logic.
- Check the
Retry-Afterheader in the response body to determine how long to wait. - Avoid polling the update status immediately after a write. The
PUTresponse is sufficient confirmation of success.