How to Configure Web Messaging Deployment Colors and Launcher Position via API
What You Will Build
- You will programmatically create or update a Web Messaging deployment configuration to set specific hex colors for the chat bubble and launcher, and define the precise screen position of the launcher widget.
- This tutorial uses the Genesys Cloud CX API (
/api/v2/webchat/deployments) and the Python SDK (genesyscloud). - The programming language covered is Python 3.9+.
Prerequisites
- OAuth Client Type: A Client Credentials OAuth client with the scope
webchat:deployment:write. - SDK Version:
genesyscloudPython SDK version 120.0.0 or later. - Language/Runtime: Python 3.9+ installed on your local machine.
- External Dependencies:
pip install genesyscloud
Authentication Setup
Genesys Cloud uses OAuth 2.0 for authentication. For programmatic access, the Client Credentials flow is the standard approach. You must store your OAuth Client ID and Secret securely. This tutorial assumes you are using environment variables for these credentials.
First, install the SDK and import the necessary modules. The genesyscloud SDK handles token acquisition and refresh automatically if you initialize the API client correctly.
import os
import logging
from typing import Optional
from genesyscloud import Configuration, ApiClient, WebchatApi
from genesyscloud.api_exception import ApiException
# Configure logging to see HTTP requests/responses if needed
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
def get_genesys_webchat_api() -> WebchatApi:
"""
Initializes and returns a configured WebchatApi client.
"""
# Retrieve credentials from environment variables
client_id = os.getenv("GENESYS_OAUTH_CLIENT_ID")
client_secret = os.getenv("GENESYS_OAUTH_CLIENT_SECRET")
if not client_id or not client_secret:
raise ValueError("GENESYS_OAUTH_CLIENT_ID and GENESYS_OAUTH_CLIENT_SECRET must be set.")
# Create the configuration object
config = Configuration()
config.oauth_client_id = client_id
config.oauth_client_secret = client_secret
# The region must match your Genesys Cloud organization
# Common regions: us-east-1, eu-west-1, ap-southeast-2
config.host = "api.us-east-1.mypurecloud.com"
# Initialize the API client
api_client = ApiClient(configuration=config)
# Return the specific Webchat API instance
return WebchatApi(api_client)
# Verify the connection and token generation
try:
webchat_api = get_genesys_webchat_api()
logger.info("Successfully authenticated with Genesys Cloud Webchat API.")
except Exception as e:
logger.error(f"Failed to initialize API client: {e}")
exit(1)
Implementation
Step 1: Retrieve or Create the Deployment ID
Before configuring colors, you need a valid deploymentId. If you already have a deployment, you can list them to find the ID. If you do not have one, you must create a new deployment configuration.
OAuth Scope Required: webchat:deployment:read (for listing) or webchat:deployment:write (for creating).
Option A: List Existing Deployments
def list_deployments(webchat_api: WebchatApi) -> list:
"""
Retrieves a list of existing webchat deployments.
"""
try:
# The list_deployments method returns a WebchatDeploymentEntityListing
response = webchat_api.post_webchat_deployments_list(
body={
"pageSize": 20,
"pageNumber": 1
}
)
if response.entities and len(response.entities) > 0:
return response.entities
else:
return []
except ApiError as e:
logger.error(f"Error listing deployments: {e.status} - {e.reason}")
raise
Option B: Create a New Deployment Configuration
If you need a fresh deployment to configure from scratch, use the create endpoint. Note that you must provide a unique name and at least one valid channel type (e.g., webchat).
from genesyscloud.models import WebchatDeploymentCreateRequest
def create_new_deployment(webchat_api: WebchatApi, deployment_name: str) -> str:
"""
Creates a new webchat deployment and returns its ID.
Args:
webchat_api: The initialized WebchatApi client.
deployment_name: A unique name for the deployment.
Returns:
str: The ID of the newly created deployment.
"""
try:
# Define the basic structure required for creation
create_request = WebchatDeploymentCreateRequest(
name=deployment_name,
# You may need to specify other required fields depending on your org's schema
# Typically, you define the channels here or in a subsequent update
)
response = webchat_api.post_webchat_deployments(
body=create_request
)
logger.info(f"Created deployment with ID: {response.id}")
return response.id
except ApiError as e:
logger.error(f"Error creating deployment: {e.status} - {e.reason}")
raise
Step 2: Configure Colors and Launcher Position
The core configuration happens in the update method. The Web Messaging deployment configuration contains a chat object which holds the launcher and bubble settings.
Key Parameters:
launcher.position: Can bebottom-right,bottom-left,top-right, ortop-left.bubble.color: Hex code for the main bubble background.bubble.textColor: Hex code for the text inside the bubble.launcher.color: Hex code for the launcher icon background.launcher.textColor: Hex code for the text/icon color on the launcher.
OAuth Scope Required: webchat:deployment:write.
from genesyscloud.models import WebchatDeploymentUpdateRequest
from genesyscloud.models import WebchatDeploymentChat
from genesyscloud.models import WebchatDeploymentLauncher
from genesyscloud.models import WebchatDeploymentBubble
def configure_deployment_appearance(
webchat_api: WebchatApi,
deployment_id: str,
position: str = "bottom-right",
bubble_color: str = "#007bff",
launcher_color: str = "#0056b3",
text_color: str = "#ffffff"
) -> None:
"""
Updates a specific deployment's visual configuration.
Args:
webchat_api: The initialized WebchatApi client.
deployment_id: The ID of the deployment to update.
position: The screen position of the launcher.
bubble_color: Hex color for the chat bubble background.
launcher_color: Hex color for the launcher button background.
text_color: Hex color for text elements.
"""
# Construct the Chat Configuration Object
# Note: The SDK models map directly to the JSON structure expected by the API
launcher_config = WebchatDeploymentLauncher(
position=position,
color=launcher_color,
textColor=text_color,
# Optional: Customize the launcher icon URL if needed
# iconUrl="https://example.com/custom-icon.png"
)
bubble_config = WebchatDeploymentBubble(
color=bubble_color,
textColor=text_color,
# Optional: Customize the bubble shape or size if supported by your SDK version
)
chat_config = WebchatDeploymentChat(
launcher=launcher_config,
bubble=bubble_config
)
# Construct the Update Request
# IMPORTANT: When updating, you often need to provide the full state or specific fields.
# The PostWebchatDeploymentsUpdate endpoint typically accepts a patch-like body.
update_request = WebchatDeploymentUpdateRequest(
chat=chat_config
)
try:
# Execute the update
# The API does not return the full entity in the response for updates usually,
# but a 200 OK indicates success.
webchat_api.post_webchat_deployments_update(
deployment_id=deployment_id,
body=update_request
)
logger.info(f"Successfully updated appearance for deployment {deployment_id}")
except ApiError as e:
logger.error(f"Error updating deployment {deployment_id}: {e.status} - {e.reason}")
raise
Step 3: Validate the Configuration
After updating, it is good practice to fetch the deployment configuration again to verify that the changes persisted. This step also helps debug issues where the SDK might serialize fields incorrectly.
def get_deployment_config(webchat_api: WebchatApi, deployment_id: str) -> dict:
"""
Retrieves the full configuration of a deployment to verify updates.
"""
try:
response = webchat_api.get_webchat_deployments_deployment_id(
deployment_id=deployment_id
)
# Convert the response object to a dictionary for easier inspection
# The SDK models usually have an as_dict() method or similar
config_dict = response.to_dict() if hasattr(response, 'to_dict') else vars(response)
logger.info("Retrieved deployment configuration:")
logger.info(f"Launcher Position: {config_dict.get('chat', {}).get('launcher', {}).get('position')}")
logger.info(f"Bubble Color: {config_dict.get('chat', {}).get('bubble', {}).get('color')}")
return config_dict
except ApiError as e:
logger.error(f"Error retrieving deployment config: {e.status} - {e.reason}")
raise
Complete Working Example
This script combines all steps into a single executable workflow. It authenticates, finds an existing deployment (or creates one if none exist), updates the colors and position, and verifies the result.
import os
import logging
import sys
from typing import Optional
from genesyscloud import Configuration, ApiClient, WebchatApi
from genesyscloud.api_exception import ApiError
from genesyscloud.models import (
WebchatDeploymentUpdateRequest,
WebchatDeploymentChat,
WebchatDeploymentLauncher,
WebchatDeploymentBubble,
WebchatDeploymentCreateRequest
)
# Configure Logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
def init_api_client() -> WebchatApi:
"""Initializes the Genesys Cloud Webchat API client."""
client_id = os.getenv("GENESYS_OAUTH_CLIENT_ID")
client_secret = os.getenv("GENESYS_OAUTH_CLIENT_SECRET")
region = os.getenv("GENESYS_REGION", "us-east-1")
if not client_id or not client_secret:
logger.error("Missing environment variables: GENESYS_OAUTH_CLIENT_ID, GENESYS_OAUTH_CLIENT_SECRET")
sys.exit(1)
config = Configuration()
config.oauth_client_id = client_id
config.oauth_client_secret = client_secret
config.host = f"api.{region}.mypurecloud.com"
api_client = ApiClient(configuration=config)
return WebchatApi(api_client)
def find_or_create_deployment(webchat_api: WebchatApi, target_name: str) -> str:
"""Finds an existing deployment by name or creates a new one."""
# Step 1: Try to find existing
try:
list_response = webchat_api.post_webchat_deployments_list(body={"pageSize": 100, "pageNumber": 1})
if list_response.entities:
for dep in list_response.entities:
if dep.name == target_name:
logger.info(f"Found existing deployment: {dep.id}")
return dep.id
except ApiError as e:
logger.warning(f"Could not list deployments: {e}")
# Step 2: Create new if not found
logger.info(f"Creating new deployment: {target_name}")
try:
create_req = WebchatDeploymentCreateRequest(name=target_name)
response = webchat_api.post_webchat_deployments(body=create_req)
return response.id
except ApiError as e:
logger.error(f"Failed to create deployment: {e}")
sys.exit(1)
def update_appearance(webchat_api: WebchatApi, deployment_id: str) -> None:
"""Updates the deployment with custom colors and position."""
# Define Custom Styling
CUSTOM_CONFIG = {
"position": "bottom-right", # Options: bottom-right, bottom-left, top-right, top-left
"bubble_color": "#FF5733", # Vibrant Orange
"launcher_color": "#C70039", # Deep Red
"text_color": "#FFFFFF" # White Text
}
logger.info(f"Updating deployment {deployment_id} with custom appearance...")
# Build the nested model objects
launcher = WebchatDeploymentLauncher(
position=CUSTOM_CONFIG["position"],
color=CUSTOM_CONFIG["launcher_color"],
textColor=CUSTOM_CONFIG["text_color"]
)
bubble = WebchatDeploymentBubble(
color=CUSTOM_CONFIG["bubble_color"],
textColor=CUSTOM_CONFIG["text_color"]
)
chat = WebchatDeploymentChat(
launcher=launcher,
bubble=bubble
)
update_req = WebchatDeploymentUpdateRequest(chat=chat)
try:
# Perform the update
webchat_api.post_webchat_deployments_update(
deployment_id=deployment_id,
body=update_req
)
logger.info("Appearance update sent successfully.")
except ApiError as e:
logger.error(f"Update failed: {e.status} {e.reason}")
sys.exit(1)
def verify_update(webchat_api: WebchatApi, deployment_id: str) -> None:
"""Fetches and prints the updated configuration."""
try:
response = webchat_api.get_webchat_deployments_deployment_id(deployment_id=deployment_id)
# Accessing nested attributes depending on SDK version structure
# In newer SDKs, you access properties directly
chat_obj = response.chat
if chat_obj:
launcher_obj = chat_obj.launcher
bubble_obj = chat_obj.bubble
if launcher_obj and bubble_obj:
logger.info("--- Verification ---")
logger.info(f"Launcher Position: {launcher_obj.position}")
logger.info(f"Launcher Color: {launcher_obj.color}")
logger.info(f"Bubble Color: {bubble_obj.color}")
logger.info("--------------------")
else:
logger.warning("Chat object exists but launcher/bubble details are missing or null.")
else:
logger.warning("Chat configuration object is null.")
except ApiError as e:
logger.error(f"Verification failed: {e}")
def main():
"""Main execution block."""
# 1. Initialize API
webchat_api = init_api_client()
# 2. Get Deployment ID
deployment_name = "Custom Styled Webchat"
deployment_id = find_or_create_deployment(webchat_api, deployment_name)
if not deployment_id:
logger.error("No deployment ID obtained.")
sys.exit(1)
# 3. Update Appearance
update_appearance(webchat_api, deployment_id)
# 4. Verify
verify_update(webchat_api, deployment_id)
if __name__ == "__main__":
main()
Common Errors & Debugging
Error: 401 Unauthorized
- Cause: The OAuth token is expired, invalid, or the client credentials are incorrect.
- Fix: Ensure
GENESYS_OAUTH_CLIENT_IDandGENESYS_OAUTH_CLIENT_SECRETare correct. Check that the OAuth client has thewebchat:deployment:writescope assigned in the Genesys Cloud Admin Console under Developers > OAuth clients. - Code Fix: The
genesyscloudSDK handles token refresh automatically. If you are implementing raw HTTP requests, ensure you are fetching a new access token before making the API call.
Error: 403 Forbidden
- Cause: The OAuth client lacks the specific scope
webchat:deployment:write. - Fix: Go to the Genesys Cloud Admin Console, navigate to Developers > OAuth clients, select your client, and add the
webchat:deployment:writescope. Save the changes. Note that scope changes may take a few minutes to propagate.
Error: 400 Bad Request - Invalid Position
- Cause: The
positionfield inWebchatDeploymentLaunchercontains a value not supported by the API. - Fix: Valid values are strictly
bottom-right,bottom-left,top-right, andtop-left. Ensure there are no typos or extra whitespace in the string value.
Error: 400 Bad Request - Invalid Hex Color
- Cause: The color strings do not match the expected hex format (e.g.,
#FFFFFF). - Fix: Ensure all color values start with a
#and are followed by exactly 6 hexadecimal digits. The API may reject 3-digit hex codes (e.g.,#FFF) or named colors (e.g.,red). Always use 6-digit hex codes.
Error: 429 Too Many Requests
- Cause: You have exceeded the rate limit for the Webchat API endpoints.
- Fix: Implement exponential backoff in your retry logic. The
genesyscloudSDK does not automatically retry 429s in all versions, so you may need to wrap the API call in a retry decorator.
import time
def retry_on_429(func, *args, max_retries=3, **kwargs):
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except ApiError as e:
if e.status == 429:
wait_time = 2 ** attempt # Exponential backoff: 1s, 2s, 4s
logger.warning(f"Rate limited (429). Retrying in {wait_time} seconds...")
time.sleep(wait_time)
else:
raise
raise Exception("Max retries exceeded for 429 errors")