Send Canned Responses in Genesys Cloud Chat via the Conversations API

Send Canned Responses in Genesys Cloud Chat via the Conversations API

What You Will Build

  • A script that authenticates to Genesys Cloud and sends a pre-configured canned response to an active chat conversation.
  • This tutorial uses the Genesys Cloud Platform API v2, specifically the Conversations and Messaging endpoints.
  • The implementation uses Python with the requests library and the official Genesys Cloud Python SDK.

Prerequisites

  • OAuth Client Type: Confidential Client (Client Credentials Grant) or Authorization Code Grant with PKCE. For this backend automation example, we use Client Credentials.
  • Required Scopes:
    • conversation:chat:write (to send messages in a chat)
    • cannedresponse:read (to fetch the canned response text if needed, though often you just need the ID)
    • user:read (optional, for debugging user context)
  • SDK Version: genesys-cloud-purecloud-platform-client >= 110.0.0
  • Language/Runtime: Python 3.8+
  • External Dependencies:
    • requests
    • genesys-cloud-purecloud-platform-client
    • pyyaml (for optional config loading)

Authentication Setup

Genesys Cloud APIs require OAuth 2.0 authentication. For server-to-server interactions (like sending a canned response from a bot or backend service), the Client Credentials Grant is the standard flow. You must obtain an access token and refresh it before expiration.

The following code sets up the client and handles token acquisition. We use the SDK’s built-in authentication manager, which simplifies token caching and refresh logic.

import os
from purecloudplatform.client import PlatformClient
from purecloudplatform.client.rest import ApiException

def get_platform_client(client_id: str, client_secret: str, env_name: str = "mypurecloud.com") -> PlatformClient:
    """
    Initializes and returns a configured Genesys Cloud PlatformClient.
    
    Args:
        client_id: The OAuth client ID.
        client_secret: The OAuth client secret.
        env_name: The Genesys Cloud environment (e.g., 'mypurecloud.com').
    
    Returns:
        PlatformClient instance ready for API calls.
    """
    client = PlatformClient()
    
    # Configure the OAuth settings
    client.set_config(
        client_id=client_id,
        client_secret=client_secret,
        env_name=env_name
    )
    
    # Get the access token. The SDK handles caching and automatic refresh.
    try:
        token = client.get_access_token()
        if not token:
            raise Exception("Failed to obtain access token")
        return client
    except ApiException as e:
        print(f"Authentication failed: {e}")
        raise

# Load credentials from environment variables for security
CLIENT_ID = os.getenv("GENESYS_CLIENT_ID")
CLIENT_SECRET = os.getenv("GENESYS_CLIENT_SECRET")

if not CLIENT_ID or not CLIENT_SECRET:
    raise ValueError("GENESYS_CLIENT_ID and GENESYS_CLIENT_SECRET environment variables must be set.")

platform_client = get_platform_client(CLIENT_ID, CLIENT_SECRET)

Implementation

Step 1: Identify the Conversation and Canned Response

Before sending a message, you must identify the specific chat conversation ID and the canned response ID. In a real-world scenario, you might receive the conversation ID from a webhook or event stream. For this tutorial, we assume you have the conversation_id and the canned_response_id.

If you do not have the canned response ID, you can search for it using the Canned Responses API.

from purecloudplatform.client.api import CannedresponsesApi
from purecloudplatform.client.rest import ApiException

def find_canned_response_by_name(api_client: PlatformClient, canned_response_name: str) -> str:
    """
    Searches for a canned response by name and returns its ID.
    
    Args:
        api_client: The PlatformClient instance.
        canned_response_name: The name of the canned response to find.
        
    Returns:
        The ID of the canned response.
        
    Raises:
        ApiException: If the API call fails.
        ValueError: If no canned response is found.
    """
    canned_responses_api = CannedresponsesApi(api_client)
    
    try:
        # Search for canned responses. Limit to 1 for efficiency.
        response = canned_responses_api.post_im_cannedresponses_search(
            body={
                "query": canned_response_name,
                "limit": 1
            }
        )
        
        if response.results and len(response.results) > 0:
            return response.results[0].id
        else:
            raise ValueError(f"No canned response found with name: {canned_response_name}")
            
    except ApiException as e:
        print(f"Error searching for canned response: {e}")
        raise

# Example: Find a canned response named "Welcome"
# canned_response_id = find_canned_response_by_name(platform_client, "Welcome")

Step 2: Construct the Chat Message Payload

To send a message in a chat conversation, you use the POST /api/v2/conversations/chats/messages endpoint. The request body must be a ChatMessageRequest object.

Key fields in the request:

  • text: The content of the message. If you are using a canned response, you typically fetch the text content of the canned response and insert it here. Alternatively, if you are just sending a static string, you put that here.
  • fromUserId: The ID of the user (agent or bot) sending the message. This is crucial for routing and display purposes.
  • type: Usually user for agent/bot messages.

Note: Genesys Cloud does not have a specific “send canned response” API endpoint for chats. You fetch the canned response text and send it as a standard chat message. This gives you control over formatting and dynamic content insertion.

from purecloudplatform.client.api import ConversationsApi
from purecloudplatform.client.rest import ApiException
from purecloudplatform.client.model.chat_message_request import ChatMessageRequest
from purecloudplatform.client.model.chat_message_participant import ChatMessageParticipant

def send_canned_response_message(
    api_client: PlatformClient, 
    conversation_id: str, 
    canned_response_text: str, 
    sender_user_id: str
) -> dict:
    """
    Sends a chat message containing the canned response text.
    
    Args:
        api_client: The PlatformClient instance.
        conversation_id: The ID of the chat conversation.
        canned_response_text: The text content of the canned response.
        sender_user_id: The ID of the user sending the message.
        
    Returns:
        The response from the API.
        
    Raises:
        ApiException: If the API call fails.
    """
    conversations_api = ConversationsApi(api_client)
    
    # Construct the participant object for the sender
    sender = ChatMessageParticipant(
        id=sender_user_id,
        type="user"
    )
    
    # Construct the chat message request
    message_request = ChatMessageRequest(
        text=canned_response_text,
        from_user_id=sender_user_id,
        type="user"
    )
    
    try:
        # Send the message to the conversation
        response = conversations_api.post_conversations_chat_messages(
            conversation_id=conversation_id,
            body=message_request
        )
        
        print(f"Message sent successfully. Message ID: {response.id}")
        return response
        
    except ApiException as e:
        if e.status == 404:
            print(f"Conversation {conversation_id} not found.")
        elif e.status == 403:
            print(f"Insufficient permissions to send message in conversation {conversation_id}.")
        elif e.status == 429:
            print("Rate limited. Please retry after the Retry-After header duration.")
        else:
            print(f"Error sending message: {e}")
        raise

# Example: Send the message
# conversation_id = "123e4567-e89b-12d3-a456-426614174000"
# sender_user_id = "987fcdeb-51a2-3b4c-d6e7-f89012345678"
# canned_text = "Hello! How can I help you today?"
# send_canned_response_message(platform_client, conversation_id, canned_text, sender_user_id)

Step 3: Fetch Canned Response Text and Send

In this final step, we combine the previous functions to fetch the canned response text and send it. We also add error handling for common issues like invalid IDs or network errors.

from purecloudplatform.client.api import CannedresponsesApi

def send_canned_response_via_id(
    api_client: PlatformClient, 
    conversation_id: str, 
    canned_response_id: str, 
    sender_user_id: str
) -> dict:
    """
    Fetches a canned response by ID and sends its text to a chat conversation.
    
    Args:
        api_client: The PlatformClient instance.
        conversation_id: The ID of the chat conversation.
        canned_response_id: The ID of the canned response.
        sender_user_id: The ID of the user sending the message.
        
    Returns:
        The response from the message send API.
        
    Raises:
        ApiException: If the API call fails.
        ValueError: If the canned response is not found.
    """
    canned_responses_api = CannedresponsesApi(api_client)
    
    # Step 1: Get the canned response details
    try:
        canned_response = canned_responses_api.get_cannedresponse(
            canned_response_id=canned_response_id
        )
        
        if not canned_response or not canned_response.text:
            raise ValueError(f"Canned response {canned_response_id} has no text.")
            
        canned_text = canned_response.text
        
    except ApiException as e:
        if e.status == 404:
            raise ValueError(f"Canned response {canned_response_id} not found.")
        else:
            raise
    
    # Step 2: Send the message
    return send_canned_response_message(
        api_client=api_client,
        conversation_id=conversation_id,
        canned_response_text=canned_text,
        sender_user_id=sender_user_id
    )

Complete Working Example

The following script combines all the steps into a single, runnable example. It fetches a canned response by name, sends it to a specified chat conversation, and handles errors.

import os
import sys
from purecloudplatform.client import PlatformClient
from purecloudplatform.client.rest import ApiException
from purecloudplatform.client.api import CannedresponsesApi, ConversationsApi
from purecloudplatform.client.model.chat_message_request import ChatMessageRequest

def get_platform_client(client_id: str, client_secret: str, env_name: str = "mypurecloud.com") -> PlatformClient:
    client = PlatformClient()
    client.set_config(
        client_id=client_id,
        client_secret=client_secret,
        env_name=env_name
    )
    try:
        token = client.get_access_token()
        if not token:
            raise Exception("Failed to obtain access token")
        return client
    except ApiException as e:
        print(f"Authentication failed: {e}")
        sys.exit(1)

def find_canned_response_by_name(api_client: PlatformClient, canned_response_name: str) -> str:
    canned_responses_api = CannedresponsesApi(api_client)
    try:
        response = canned_responses_api.post_im_cannedresponses_search(
            body={
                "query": canned_response_name,
                "limit": 1
            }
        )
        if response.results and len(response.results) > 0:
            return response.results[0].id
        else:
            raise ValueError(f"No canned response found with name: {canned_response_name}")
    except ApiException as e:
        print(f"Error searching for canned response: {e}")
        raise

def send_canned_response_message(
    api_client: PlatformClient, 
    conversation_id: str, 
    canned_response_text: str, 
    sender_user_id: str
) -> dict:
    conversations_api = ConversationsApi(api_client)
    message_request = ChatMessageRequest(
        text=canned_response_text,
        from_user_id=sender_user_id,
        type="user"
    )
    try:
        response = conversations_api.post_conversations_chat_messages(
            conversation_id=conversation_id,
            body=message_request
        )
        print(f"Message sent successfully. Message ID: {response.id}")
        return response
    except ApiException as e:
        print(f"Error sending message: {e}")
        raise

def main():
    # Configuration
    CLIENT_ID = os.getenv("GENESYS_CLIENT_ID")
    CLIENT_SECRET = os.getenv("GENESYS_CLIENT_SECRET")
    CONVERSATION_ID = os.getenv("GENESYS_CONVERSATION_ID")
    SENDER_USER_ID = os.getenv("GENESYS_SENDER_USER_ID")
    CANNED_RESPONSE_NAME = os.getenv("GENESYS_CANNED_RESPONSE_NAME", "Welcome")
    
    if not all([CLIENT_ID, CLIENT_SECRET, CONVERSATION_ID, SENDER_USER_ID]):
        print("Missing required environment variables.")
        sys.exit(1)
        
    try:
        # 1. Authenticate
        platform_client = get_platform_client(CLIENT_ID, CLIENT_SECRET)
        
        # 2. Find Canned Response
        canned_response_id = find_canned_response_by_name(platform_client, CANNED_RESPONSE_NAME)
        print(f"Found canned response ID: {canned_response_id}")
        
        # 3. Get Canned Response Text
        canned_responses_api = CannedresponsesApi(platform_client)
        canned_response = canned_responses_api.get_cannedresponse(canned_response_id=canned_response_id)
        canned_text = canned_response.text
        
        # 4. Send Message
        send_canned_response_message(
            api_client=platform_client,
            conversation_id=CONVERSATION_ID,
            canned_response_text=canned_text,
            sender_user_id=SENDER_USER_ID
        )
        
    except Exception as e:
        print(f"An error occurred: {e}")
        sys.exit(1)

if __name__ == "__main__":
    main()

Common Errors & Debugging

Error: 401 Unauthorized

  • Cause: The OAuth token is invalid, expired, or missing.
  • Fix: Ensure the GENESYS_CLIENT_ID and GENESYS_CLIENT_SECRET are correct. Check that the client has the required scopes (conversation:chat:write). The SDK handles token refresh, but if the client credentials are wrong, the initial token fetch will fail.

Error: 403 Forbidden

  • Cause: The OAuth client or user does not have permission to send messages in the specified conversation.
  • Fix: Verify that the sender_user_id is a valid user ID and that the user is associated with the conversation. Ensure the OAuth client has the conversation:chat:write scope. If using a bot user, ensure it has the necessary permissions.

Error: 404 Not Found

  • Cause: The conversation_id or canned_response_id is invalid.
  • Fix: Double-check the IDs. Use the Genesys Cloud Admin UI to verify the existence of the canned response and the conversation.

Error: 429 Too Many Requests

  • Cause: You have exceeded the API rate limit.
  • Fix: Implement retry logic with exponential backoff. The API response includes a Retry-After header indicating the number of seconds to wait.
import time
from purecloudplatform.client.rest import ApiException

def send_with_retry(api_call_func, max_retries=3):
    for attempt in range(max_retries):
        try:
            return api_call_func()
        except ApiException as e:
            if e.status == 429:
                retry_after = int(e.headers.get('Retry-After', 1))
                print(f"Rate limited. Retrying in {retry_after} seconds...")
                time.sleep(retry_after)
            else:
                raise
    raise Exception("Max retries exceeded")

Official References