How to Configure Web Messaging Deployment Colors and Launcher Position via API

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: genesyscloud Python 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 be bottom-right, bottom-left, top-right, or top-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_ID and GENESYS_OAUTH_CLIENT_SECRET are correct. Check that the OAuth client has the webchat:deployment:write scope assigned in the Genesys Cloud Admin Console under Developers > OAuth clients.
  • Code Fix: The genesyscloud SDK 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:write scope. Save the changes. Note that scope changes may take a few minutes to propagate.

Error: 400 Bad Request - Invalid Position

  • Cause: The position field in WebchatDeploymentLauncher contains a value not supported by the API.
  • Fix: Valid values are strictly bottom-right, bottom-left, top-right, and top-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 genesyscloud SDK 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")

Official References