How to programmatically configure Web Messaging deployment colors and launcher position

How to programmatically configure Web Messaging deployment colors and launcher position

What You Will Build

  • One sentence: The code creates or updates a Genesys Cloud CX Web Messaging deployment with specific hex color codes and a defined launcher button position.
  • One sentence: This uses the Genesys Cloud CX PureCloud Platform Client V2 SDK and the Deployments API.
  • One sentence: The programming language covered is Python.

Prerequisites

  • OAuth client type: Public or Confidential client with the webmessaging:deployments:write scope.
  • SDK version: genesys-cloud-sdk-purecloud-platform-client-v2 >= 150.0.0.
  • Language/runtime requirements: Python 3.9+.
  • External dependencies: genesys-cloud-sdk-purecloud-platform-client-v2, python-dotenv (for secure credential management).

Authentication Setup

Genesys Cloud CX APIs require OAuth 2.0 Bearer tokens. For server-to-server interactions (like configuration scripts), the Client Credentials flow is the standard. You must install the SDK and set up environment variables for your Client ID and Secret.

Install the dependency:

pip install genesys-cloud-sdk-purecloud-platform-client-v2 python-dotenv

Create a .env file in your project root:

GENESYS_CLOUD_CLIENT_ID=your_client_id_here
GENESYS_CLOUD_CLIENT_SECRET=your_client_secret_here
GENESYS_CLOUD_REGION=eus05 # or us-east-1, eu-west-1, etc.

Initialize the SDK client in your Python script. The SDK handles token acquisition and refreshing automatically.

import os
from dotenv import load_dotenv
from purecloud_platform_client_v2 import Configuration, ApiClient, WebMessagingApi

load_dotenv()

def get_web_messaging_api_client():
    """
    Initializes and returns the WebMessagingApi client.
    """
    config = Configuration()
    config.host = f"https://{os.getenv('GENESYS_CLOUD_REGION')}.mypurecloud.com/api/v2"
    config.client_id = os.getenv('GENESYS_CLOUD_CLIENT_ID')
    config.client_secret = os.getenv('GENESYS_CLOUD_CLIENT_SECRET')
    
    api_client = ApiClient(configuration=config)
    return WebMessagingApi(api_client)

web_messaging_api = get_web_messaging_api_client()

Implementation

Step 1: Retrieve existing deployments or create a new one

Before updating colors, you must know the Deployment ID. If you are building a fresh integration, you may need to create the deployment first. If one already exists, you must fetch it to get its ID and current state, as updates are partial (PATCH) or full (PUT) operations depending on the specific API version behavior. The WebMessagingApi uses put_web_messaging_deployment to upsert a deployment.

First, let us define the configuration payload. The Web Messaging deployment configuration is nested deeply. The critical objects are launcher and widget.

from purecloud_platform_client_v2.models import (
    WebMessagingDeployment,
    WebMessagingDeploymentProperties,
    WebMessagingLauncherConfig,
    WebMessagingWidgetConfig,
    WebMessagingThemeConfig
)

def build_deployment_config(deployment_id: str, name: str, language: str = "en-US"):
    """
    Constructs the WebMessagingDeployment object with custom colors and position.
    """
    
    # 1. Define the Launcher Configuration
    # This controls the floating button that opens the chat.
    launcher_config = WebMessagingLauncherConfig(
        # Position: 'bottom-right', 'bottom-left', 'top-right', 'top-left'
        position="bottom-left", 
        # Offset from the edge in pixels
        horizontal_offset=20,
        vertical_offset=20,
        # Show the launcher button
        show=True,
        # Custom icon URL (optional). If null, uses default Genesys icon.
        icon=None 
    )

    # 2. Define the Theme Configuration
    # This controls colors for both the launcher and the widget header/body.
    theme_config = WebMessagingThemeConfig(
        # Primary color (launcher background, header background)
        primary_color="#FF5733",
        # Secondary color (text on primary background, often white or black)
        secondary_color="#FFFFFF",
        # Button text color
        button_text_color="#FFFFFF",
        # Widget background color
        widget_background_color="#F4F4F4",
        # Widget text color
        widget_text_color="#333333",
        # Header background color (can override primary)
        header_background_color="#FF5733",
        # Header text color
        header_text_color="#FFFFFF"
    )

    # 3. Define the Widget Configuration
    # This controls the chat window itself.
    widget_config = WebMessagingWidgetConfig(
        # Title displayed in the chat window header
        title="Customer Support",
        # Welcome message shown when chat opens
        welcome_message="Hello! How can we help you today?",
        # Auto-open the widget on page load (optional)
        auto_open=False,
        # Theme applied to the widget
        theme=theme_config
    )

    # 4. Assemble the Deployment Properties
    properties = WebMessagingDeploymentProperties(
        launcher=launcher_config,
        widget=widget_config,
        # Ensure the deployment is active
        active=True,
        # Language for the interface
        language=language
    )

    # 5. Create the Deployment Object
    deployment = WebMessagingDeployment(
        id=deployment_id,
        name=name,
        properties=properties
    )

    return deployment

Step 2: Execute the Update via API

The put_web_messaging_deployment method is used to create or update a deployment. If the id provided does not exist, Genesys Cloud creates a new one. If it exists, it updates the existing one with the provided properties.

OAuth Scope Required: webmessaging:deployments:write

def update_deployment(deployment: WebMessagingDeployment):
    """
    Sends the deployment configuration to Genesys Cloud.
    """
    try:
        # The API endpoint is /api/v2/webmessaging/deployments/{deploymentId}
        result = web_messaging_api.put_web_messaging_deployment(
            deployment_id=deployment.id,
            body=deployment
        )
        print(f"Deployment '{result.name}' updated successfully with ID: {result.id}")
        return result
    except Exception as e:
        # Handle API errors
        print(f"Error updating deployment: {e}")
        if hasattr(e, 'status'):
            print(f"HTTP Status: {e.status}")
        if hasattr(e, 'reason'):
            print(f"Reason: {e.reason}")
        if hasattr(e, 'body'):
            print(f"Response Body: {e.body}")
        raise e

Step 3: Handling Idempotency and Existing IDs

In production, you rarely hardcode an ID. You typically fetch the deployment by name or check if it exists. Since there is no direct “get by name” endpoint for deployments, you usually list all deployments and find the one you want, or you manage the ID in your own database.

Here is how to list deployments to find the correct ID:

def get_deployment_by_name(name: str):
    """
    Lists all web messaging deployments and returns the one matching the name.
    """
    try:
        # GET /api/v2/webmessaging/deployments
        # Scope: webmessaging:deployments:read
        result = web_messaging_api.get_web_messaging_deployments()
        
        if result.entities:
            for deployment in result.entities:
                if deployment.name == name:
                    return deployment
        return None
    except Exception as e:
        print(f"Error listing deployments: {e}")
        return None

Complete Working Example

This script combines authentication, ID resolution, configuration building, and the API call. It is designed to be idempotent: if the deployment exists, it updates it; if not, it creates it.

import os
import sys
from dotenv import load_dotenv
from purecloud_platform_client_v2 import Configuration, ApiClient, WebMessagingApi
from purecloud_platform_client_v2.models import (
    WebMessagingDeployment,
    WebMessagingDeploymentProperties,
    WebMessagingLauncherConfig,
    WebMessagingWidgetConfig,
    WebMessagingThemeConfig
)

load_dotenv()

def initialize_client():
    config = Configuration()
    region = os.getenv('GENESYS_CLOUD_REGION', 'eus05')
    config.host = f"https://{region}.mypurecloud.com/api/v2"
    config.client_id = os.getenv('GENESYS_CLOUD_CLIENT_ID')
    config.client_secret = os.getenv('GENESYS_CLOUD_CLIENT_SECRET')
    
    if not config.client_id or not config.client_secret:
        raise ValueError("GENESYS_CLOUD_CLIENT_ID and GENESYS_CLOUD_CLIENT_SECRET must be set in .env")
        
    api_client = ApiClient(configuration=config)
    return WebMessagingApi(api_client)

def create_custom_deployment(api_client: WebMessagingApi, deployment_name: str):
    # Step 1: Check if deployment exists
    existing_deployment = None
    try:
        list_result = api_client.get_web_messaging_deployments()
        if list_result.entities:
            for dep in list_result.entities:
                if dep.name == deployment_name:
                    existing_deployment = dep
                    break
    except Exception as e:
        print(f"Warning: Could not list deployments. Assuming new creation. Error: {e}")

    deployment_id = existing_deployment.id if existing_deployment else None
    # If creating new, Genesys generates the ID. We do not need to provide it in the request body for creation, 
    # but the SDK model requires it for updates. The SDK handles this distinction in put_ methods usually, 
    # but for clarity, we pass None for ID if new, and the SDK constructs the POST request.
    # Note: The purecloud_platform_client_v2 SDK put_ method typically handles POST vs PUT based on ID presence.

    # Step 2: Define Custom Styling
    theme_config = WebMessagingThemeConfig(
        primary_color="#0056b3",      # Deep Blue
        secondary_color="#ffffff",    # White
        button_text_color="#ffffff",
        widget_background_color="#f8f9fa",
        widget_text_color="#212529",
        header_background_color="#0056b3",
        header_text_color="#ffffff"
    )

    launcher_config = WebMessagingLauncherConfig(
        position="bottom-right",     # Changed to bottom-right for this example
        horizontal_offset=20,
        vertical_offset=20,
        show=True
    )

    widget_config = WebMessagingWidgetConfig(
        title="Tech Support Chat",
        welcome_message="Hi there! An agent will be with you shortly.",
        auto_open=False,
        theme=theme_config
    )

    properties = WebMessagingDeploymentProperties(
        launcher=launcher_config,
        widget=widget_config,
        active=True,
        language="en-US"
    )

    # Step 3: Build Deployment Object
    if deployment_id:
        # Update existing
        deployment = WebMessagingDeployment(
            id=deployment_id,
            name=deployment_name,
            properties=properties
        )
    else:
        # Create new
        deployment = WebMessagingDeployment(
            name=deployment_name,
            properties=properties
        )

    # Step 4: Execute API Call
    try:
        if deployment_id:
            print(f"Updating existing deployment: {deployment_id}")
            result = api_client.put_web_messaging_deployment(deployment_id=deployment_id, body=deployment)
        else:
            print("Creating new deployment...")
            # Note: For creation, the SDK might route to POST /api/v2/webmessaging/deployments
            # The put_ method in this SDK often handles both. If it strictly requires ID for PUT, 
            # use post_web_messaging_deployment for creation.
            # Checking SDK docs: post_web_messaging_deployment is for creation.
            result = api_client.post_web_messaging_deployment(body=deployment)
        
        print(f"Success! Deployment ID: {result.id}")
        print(f"Launcher Position: {result.properties.launcher.position}")
        print(f"Primary Color: {result.properties.widget.theme.primary_color}")
        return result

    except Exception as e:
        print(f"Failed to configure deployment: {e}")
        if hasattr(e, 'body'):
            print(f"API Error Details: {e.body}")
        sys.exit(1)

if __name__ == "__main__":
    client = initialize_client()
    create_custom_deployment(client, "My Custom Styled Chat")

Common Errors & Debugging

Error: 401 Unauthorized

  • What causes it: The Client ID or Client Secret in your .env file is incorrect, or the client has not been authorized in the Genesys Cloud Admin Console under Admin > Security > OAuth clients.
  • How to fix it: Verify the credentials match the client created in Genesys Cloud. Ensure the client status is “Active”.
  • Code showing the fix: Check the initialize_client function for empty variables.

Error: 403 Forbidden

  • What causes it: The OAuth client does not have the required scope webmessaging:deployments:write.
  • How to fix it: Go to Admin > Security > OAuth clients, select your client, and add the scope webmessaging:deployments:write under the “Scopes” tab. Save and re-run.
  • Code showing the fix: No code change required. This is an admin configuration fix.

Error: 400 Bad Request - Invalid Hex Color

  • What causes it: The primary_color or other color fields contain an invalid hex string (e.g., missing the # or containing non-hex characters).
  • How to fix it: Ensure all color strings start with # and are followed by 3 or 6 valid hexadecimal digits (0-9, A-F).
  • Code showing the fix:
    # Incorrect
    theme_config = WebMessagingThemeConfig(primary_color="FF5733") 
    
    # Correct
    theme_config = WebMessagingThemeConfig(primary_color="#FF5733")
    

Error: 429 Too Many Requests

  • What causes it: You are calling the API too frequently. Genesys Cloud enforces rate limits.
  • How to fix it: Implement exponential backoff in your retry logic. The SDK does not automatically retry 429s by default in all configurations, so you should wrap the call in a retry loop.
  • Code showing the fix:
    import time
    
    def retry_with_backoff(func, *args, max_retries=3, **kwargs):
        for attempt in range(max_retries):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                if hasattr(e, 'status') and e.status == 429:
                    wait_time = 2 ** attempt
                    print(f"Rate limited. Waiting {wait_time} seconds...")
                    time.sleep(wait_time)
                else:
                    raise e
        raise Exception("Max retries exceeded")
    

Official References