How to configure the Web Messaging deployment to customize colors and launcher position
What You Will Build
- This tutorial demonstrates how to programmatically update a Genesys Cloud Web Messaging deployment to change the launcher button color, background color, and position on the page.
- The solution utilizes the Genesys Cloud Platform API v2 endpoint
PUT /api/v2/webdeployments/webmessaging/{webDeploymentId}. - The implementation is provided in Python using the official
genesyscloudSDK andhttpxfor direct API calls to illustrate the underlying JSON structure.
Prerequisites
- OAuth Client: A Genesys Cloud OAuth client with the following scopes:
webdeployments:webmessaging:write(Required to modify deployment configuration)webdeployments:webmessaging:read(Required to fetch existing configuration)
- SDK Version:
genesyscloudPython SDK version 1.0.0 or higher. - Runtime: Python 3.8+.
- External Dependencies:
genesyscloud:pip install genesyscloudhttpx:pip install httpx(Used for the raw HTTP example to demonstrate payload structure)pydantic: Usually included with the SDK, used for data validation.
Authentication Setup
Genesys Cloud uses OAuth 2.0 for authentication. For server-side integrations, the Client Credentials flow is the standard approach. The following code initializes the SDK with your client credentials. Ensure you replace the placeholder values with your actual Genesys Cloud credentials.
import os
from genesyscloud.platform.client.configuration import Configuration
from genesyscloud.platform.client.api_client import ApiClient
def get_api_client() -> ApiClient:
"""
Initializes and returns a configured Genesys Cloud API Client.
Returns:
ApiClient: The authenticated API client instance.
"""
# Load credentials from environment variables
client_id = os.getenv("GENESYS_CLIENT_ID")
client_secret = os.getenv("GENESYS_CLIENT_SECRET")
base_url = os.getenv("GENESYS_BASE_URL", "https://api.mypurecloud.com")
if not client_id or not client_secret:
raise ValueError("GENESYS_CLIENT_ID and GENESYS_CLIENT_SECRET must be set in environment variables.")
# Configure the platform client
configuration = Configuration(
client_id=client_id,
client_secret=client_secret,
base_path=base_url
)
api_client = ApiClient(configuration=configuration)
return api_client
The SDK handles token acquisition and refresh automatically. If the token expires during a long-running script, the ApiClient will attempt to refresh it using the stored client credentials.
Implementation
Step 1: Fetch the Existing Web Deployment Configuration
Before modifying the deployment, you must retrieve the current configuration. The Web Messaging deployment object contains nested structures for appearance, behavior, and integration settings. Modifying the entire object in one request ensures atomic updates and prevents partial state corruption.
Endpoint: GET /api/v2/webdeployments/webmessaging/{webDeploymentId}
Scope: webdeployments:webmessaging:read
from genesyscloud.platform.client.api.web_deployments_api import WebDeploymentsApi
def get_web_deployment(api_client: ApiClient, deployment_id: str) -> dict:
"""
Fetches the full configuration of a specific Web Messaging deployment.
Args:
api_client: The authenticated Genesys Cloud API client.
deployment_id: The unique identifier of the Web Messaging deployment.
Returns:
dict: The full deployment configuration object.
Raises:
Exception: If the deployment is not found or access is denied.
"""
web_deployments_api = WebDeploymentsApi(api_client)
try:
# The SDK method returns a WebDeployment object
response = web_deployments_api.get_web_deployments_web_messaging_web_deployment(
web_deployment_id=deployment_id
)
# Convert the SDK model object to a dictionary for easier manipulation
# The SDK models are Pydantic-based, so .dict() or model_dump() works
if hasattr(response, 'model_dump'):
config = response.model_dump(exclude_unset=True, by_alias=True)
else:
config = response.dict(exclude_unset=True, by_alias=True)
return config
except Exception as e:
# Handle 404 Not Found or 401 Unauthorized
if hasattr(e, 'status') and e.status == 404:
raise ValueError(f"Web Deployment with ID {deployment_id} not found.")
elif hasattr(e, 'status') and e.status == 401:
raise PermissionError("Authentication failed. Check your OAuth scopes.")
else:
raise e
Step 2: Customize Appearance and Launcher Position
The WebDeployment object contains an appearance section. Within appearance, you will find launcher and widget sub-sections.
- Launcher Position: Controlled by
launcher.position. Valid values arebottom-right,bottom-left,top-right,top-left. - Launcher Colors: Controlled by
launcher.backgroundColorandlauncher.iconColor. - Widget Colors: Controlled by
widget.backgroundColor,widget.headerColor, etc.
It is critical to preserve existing fields that you do not intend to change. Sending a partial update with PUT will overwrite the entire object. Therefore, we fetch the object, modify only the specific keys, and send the full object back.
def customize_deployment_appearance(config: dict, settings: dict) -> dict:
"""
Updates the appearance settings in the deployment configuration dictionary.
Args:
config: The current deployment configuration dictionary.
settings: A dictionary containing the new appearance settings.
Expected keys: 'launcher_position', 'launcher_bg_color',
'launcher_icon_color', 'widget_bg_color'.
Returns:
dict: The updated configuration dictionary.
"""
# Ensure the appearance structure exists
if 'appearance' not in config:
config['appearance'] = {}
appearance = config['appearance']
# Update Launcher Settings
if 'launcher' not in appearance:
appearance['launcher'] = {}
launcher = appearance['launcher']
if 'launcher_position' in settings:
valid_positions = ['bottom-right', 'bottom-left', 'top-right', 'top-left']
if settings['launcher_position'] not in valid_positions:
raise ValueError(f"Invalid position. Must be one of {valid_positions}")
launcher['position'] = settings['launcher_position']
if 'launcher_bg_color' in settings:
launcher['backgroundColor'] = settings['launcher_bg_color']
if 'launcher_icon_color' in settings:
launcher['iconColor'] = settings['launcher_icon_color']
# Update Widget Settings (Optional, but often desired for consistency)
if 'widget' not in appearance:
appearance['widget'] = {}
widget = appearance['widget']
if 'widget_bg_color' in settings:
widget['backgroundColor'] = settings['widget_bg_color']
if 'widget_header_color' in settings:
widget['headerColor'] = settings['widget_header_color']
# Assign the modified appearance back to config
config['appearance'] = appearance
return config
Step 3: Update the Deployment via API
Once the configuration dictionary is modified, you must send it back to Genesys Cloud using the PUT method. The SDK handles the serialization of the dictionary back into the WebDeployment model.
Endpoint: PUT /api/v2/webdeployments/webmessaging/{webDeploymentId}
Scope: webdeployments:webmessaging:write
def update_web_deployment(api_client: ApiClient, deployment_id: str, config: dict) -> dict:
"""
Updates the Web Messaging deployment with the new configuration.
Args:
api_client: The authenticated Genesys Cloud API client.
deployment_id: The unique identifier of the Web Messaging deployment.
config: The updated deployment configuration dictionary.
Returns:
dict: The updated deployment configuration returned by the API.
Raises:
Exception: If the update fails due to validation errors or network issues.
"""
web_deployments_api = WebDeploymentsApi(api_client)
try:
# The SDK expects a WebDeployment model object.
# We can pass the dictionary directly to the constructor if the SDK supports it,
# or we may need to manually map fields. In newer SDK versions,
# passing kwargs to the model constructor works.
# Re-instantiate the model from the dict
from genesyscloud.platform.client.model.web_deployment import WebDeployment
# Note: Depending on SDK version, you might need to use from_dict()
# or simply pass the dict if the API accepts a generic object.
# The safest approach with modern Pydantic-based SDKs:
new_deployment_model = WebDeployment.from_dict(config)
response = web_deployments_api.put_web_deployments_web_messaging_web_deployment(
web_deployment_id=deployment_id,
body=new_deployment_model
)
# Return the response dict
if hasattr(response, 'model_dump'):
return response.model_dump(by_alias=True)
else:
return response.dict(by_alias=True)
except Exception as e:
# Handle 400 Bad Request (Validation Error)
if hasattr(e, 'status') and e.status == 400:
print(f"Validation Error: {e.body}")
raise ValueError("Configuration validation failed. Check color formats and position values.")
# Handle 429 Too Many Requests
elif hasattr(e, 'status') and e.status == 429:
raise Exception("Rate limit exceeded. Please wait and retry.")
else:
raise e
Complete Working Example
The following script combines all steps into a single executable module. It fetches the current deployment, applies custom colors and position, and updates the deployment.
import os
import sys
from genesyscloud.platform.client.configuration import Configuration
from genesyscloud.platform.client.api_client import ApiClient
from genesyscloud.platform.client.api.web_deployments_api import WebDeploymentsApi
from genesyscloud.platform.client.model.web_deployment import WebDeployment
# --- Configuration ---
# Replace these with your actual values
DEPLOYMENT_ID = "your-web-deployment-id-here"
GENESYS_CLIENT_ID = os.getenv("GENESYS_CLIENT_ID")
GENESYS_CLIENT_SECRET = os.getenv("GENESYS_CLIENT_SECRET")
BASE_URL = os.getenv("GENESYS_BASE_URL", "https://api.mypurecloud.com")
# Customization Settings
CUSTOM_SETTINGS = {
"launcher_position": "bottom-left", # Move launcher to bottom left
"launcher_bg_color": "#FF5733", # Reddish-orange background
"launcher_icon_color": "#FFFFFF", # White icon
"widget_bg_color": "#FFFFFF", # White widget background
"widget_header_color": "#FF5733" # Matching header color
}
def main():
if not GENESYS_CLIENT_ID or not GENESYS_CLIENT_SECRET:
print("Error: GENESYS_CLIENT_ID and GENESYS_CLIENT_SECRET must be set in environment variables.")
sys.exit(1)
try:
# 1. Initialize API Client
configuration = Configuration(
client_id=GENESYS_CLIENT_ID,
client_secret=GENESYS_CLIENT_SECRET,
base_path=BASE_URL
)
api_client = ApiClient(configuration=configuration)
# 2. Fetch Current Configuration
print(f"Fetching configuration for deployment: {DEPLOYMENT_ID}...")
web_deployments_api = WebDeploymentsApi(api_client)
response = web_deployments_api.get_web_deployments_web_messaging_web_deployment(
web_deployment_id=DEPLOYMENT_ID
)
# Convert to dict
if hasattr(response, 'model_dump'):
config = response.model_dump(exclude_unset=True, by_alias=True)
else:
config = response.dict(exclude_unset=True, by_alias=True)
print("Current configuration fetched successfully.")
# 3. Apply Customizations
print("Applying custom appearance settings...")
# Ensure nested structures exist
if 'appearance' not in config:
config['appearance'] = {}
if 'launcher' not in config['appearance']:
config['appearance']['launcher'] = {}
if 'widget' not in config['appearance']:
config['appearance']['widget'] = {}
# Update Launcher
launcher = config['appearance']['launcher']
launcher['position'] = CUSTOM_SETTINGS['launcher_position']
launcher['backgroundColor'] = CUSTOM_SETTINGS['launcher_bg_color']
launcher['iconColor'] = CUSTOM_SETTINGS['launcher_icon_color']
# Update Widget
widget = config['appearance']['widget']
widget['backgroundColor'] = CUSTOM_SETTINGS['widget_bg_color']
widget['headerColor'] = CUSTOM_SETTINGS['widget_header_color']
# 4. Update Deployment
print("Updating deployment...")
# Re-create model from dict
new_deployment_model = WebDeployment.from_dict(config)
updated_response = web_deployments_api.put_web_deployments_web_messaging_web_deployment(
web_deployment_id=DEPLOYMENT_ID,
body=new_deployment_model
)
print("Deployment updated successfully!")
print(f"New Launcher Position: {launcher['position']}")
print(f"New Launcher Background: {launcher['backgroundColor']}")
except Exception as e:
print(f"An error occurred: {e}")
if hasattr(e, 'status'):
print(f"HTTP Status: {e.status}")
if hasattr(e, 'body'):
print(f"Response Body: {e.body}")
sys.exit(1)
if __name__ == "__main__":
main()
Common Errors & Debugging
Error: 400 Bad Request - Validation Error
What causes it: The most common cause is an invalid color format or an unsupported position value. Genesys Cloud expects CSS-compatible hex codes (e.g., #FF0000) or named colors. The position must be one of the four predefined corners.
How to fix it:
- Verify that all color values start with
#and are 6-character hex strings. - Verify that
positionis exactlybottom-right,bottom-left,top-right, ortop-left. - Check the response body for specific field validation errors.
Code Fix:
# Ensure color format is correct
def validate_hex_color(color: str) -> bool:
import re
return bool(re.match(r'^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$', color))
if not validate_hex_color(CUSTOM_SETTINGS['launcher_bg_color']):
raise ValueError("Invalid hex color format for launcher background.")
Error: 403 Forbidden
What causes it: The OAuth client used for authentication lacks the webdeployments:webmessaging:write scope.
How to fix it:
- Navigate to the Genesys Cloud Admin portal.
- Go to Admin > Security > OAuth Clients.
- Select your client.
- Add the scope
webdeployments:webmessaging:writeto the client’s scope list. - Save the changes. Note that existing tokens may need to be refreshed to pick up new scopes.
Error: 429 Too Many Requests
What causes it: Genesys Cloud APIs enforce rate limits. If you are updating multiple deployments in a loop, you may hit the limit.
How to fix it: Implement exponential backoff.
Code Fix:
import time
def update_with_retry(api_client, deployment_id, config, max_retries=3):
web_deployments_api = WebDeploymentsApi(api_client)
for attempt in range(max_retries):
try:
new_deployment_model = WebDeployment.from_dict(config)
return web_deployments_api.put_web_deployments_web_messaging_web_deployment(
web_deployment_id=deployment_id,
body=new_deployment_model
)
except Exception as e:
if hasattr(e, 'status') and e.status == 429:
wait_time = 2 ** attempt
print(f"Rate limit hit. Waiting {wait_time} seconds...")
time.sleep(wait_time)
else:
raise e
raise Exception("Max retries exceeded.")