Sending Proactive Notifications to a Customer with a Previous Web Messaging Session
What You Will Build
- A Python script that identifies a customer by their email address or phone number from historical web messaging conversations.
- A mechanism to initiate a proactive outbound web message to that customer using the Genesys Cloud Conversations API.
- The integration of the Genesys Cloud Python SDK for authentication and conversation management.
Prerequisites
- OAuth Client: A Genesys Cloud OAuth client configured with the
publicgrant type orclient_credentialsgrant type. For this tutorial, we assume aclient_credentialsflow for server-side automation. - Required Scopes:
analytics:query:read(to search historical conversations)conversation:webchat:initiate(to start a proactive web chat)user:login:read(optional, if resolving user IDs)
- SDK Version:
genesys-cloud-purecloud-platform-clientversion 170.0.0 or higher. - Language/Runtime: Python 3.9+
- External Dependencies:
genesys-cloud-purecloud-platform-clientpython-dotenv(for managing secrets)
Install the dependencies:
pip install genesys-cloud-purecloud-platform-client python-dotenv
Authentication Setup
Genesys Cloud uses OAuth 2.0 for API authentication. For server-to-server integrations, the client_credentials grant is the standard approach. The Genesys Cloud Python SDK handles token acquisition and refresh automatically when configured correctly.
Create a .env file in your project root:
GENESYS_CLOUD_REGION=us-east-1
GENESYS_CLOUD_CLIENT_ID=your_client_id
GENESYS_CLOUD_CLIENT_SECRET=your_client_secret
Initialize the SDK client:
import os
from dotenv import load_dotenv
from purecloud_platform_client import Configuration, ApiClient, AnalyticsApi, ConversationsApi
from purecloud_platform_client.rest import ApiException
load_dotenv()
def get_authenticated_client() -> ApiClient:
"""
Creates and configures the Genesys Cloud API client.
"""
config = Configuration(
client_id=os.getenv("GENESYS_CLOUD_CLIENT_ID"),
client_secret=os.getenv("GENESYS_CLOUD_CLIENT_SECRET"),
region=os.getenv("GENESYS_CLOUD_REGION", "us-east-1")
)
api_client = ApiClient(configuration=config)
return api_client
Implementation
Step 1: Identify the Customer via Historical Analytics
Before sending a proactive message, you must confirm the customer exists in your system and retrieve their previous interaction details. The Analytics API provides a robust query interface for this. We will search for conversations where the participant identity matches a known email address.
Endpoint: POST /api/v2/analytics/conversations/details/query
Scope: analytics:query:read
from purecloud_platform_client.models import (
ConversationDetailsQueryRequest,
ConversationDetailsQueryFilter,
ConversationDetailsQueryFilterEntity,
ConversationDetailsQueryFilterField
)
def find_customer_conversation(api_client: ApiClient, customer_email: str) -> dict | None:
"""
Searches for the most recent web messaging conversation for a given email.
"""
analytics_api = AnalyticsApi(api_client)
# Define the filter for the participant email
email_filter = ConversationDetailsQueryFilter(
field=ConversationDetailsQueryFilterField("participants.email"),
operator="eq",
value=customer_email
)
# Define the entity type filter to limit to Web Messaging
entity_filter = ConversationDetailsQueryFilterEntity(
field="type",
operator="eq",
value="webchat"
)
# Construct the request
query_request = ConversationDetailsQueryRequest(
filters=[email_filter, entity_filter],
size=1, # We only need the most recent one
sort_by=[{"field": "created_time", "order": "desc"}],
interval="PT1H", # Required for analytics queries, even if not strictly used in this context
from_time="2023-01-01T00:00:00Z", # Adjust as needed for your data retention policy
to_time="2025-12-31T23:59:59Z"
)
try:
response = analytics_api.post_analytics_conversations_details_query(body=query_request)
if response.entities and len(response.entities) > 0:
conversation = response.entities[0]
return {
"conversation_id": conversation.conversation_id,
"participant_id": conversation.participants[0].id if conversation.participants else None,
"email": customer_email
}
return None
except ApiException as e:
print(f"Analytics API Error: {e.status} {e.reason}")
if e.body:
print(e.body)
return None
Step 2: Initiate the Proactive Web Messaging Session
Once the customer is identified, you can initiate a proactive web chat. This requires using the ConversationsApi to create a new conversation with the webchat type. The critical parameter is the initiation_mode set to proactive and providing the customer’s identity information in the participants array.
Endpoint: POST /api/v2/conversations
Scope: conversation:webchat:initiate
from purecloud_platform_client.models import (
ConversationCreateRequest,
ConversationParticipantRequest,
ParticipantIdentity
)
def initiate_proactive_webchat(api_client: ApiClient, customer_email: str, routing_skill: str = None) -> str | None:
"""
Initiates a proactive web messaging session for the specified customer.
"""
conversations_api = ConversationsApi(api_client)
# Define the participant identity
participant_identity = ParticipantIdentity(
email=customer_email
)
# Create the participant request
participant_request = ConversationParticipantRequest(
identity=participant_identity,
type="customer"
)
# Construct the conversation creation request
# Note: For proactive webchat, you typically do not specify a queue here directly
# if you want it to route based on skills or other criteria, but you can specify a queue if needed.
# However, for pure proactive outreach, the system often requires a target queue or skill.
conversation_request = ConversationCreateRequest(
type="webchat",
initiation_mode="proactive",
participants=[participant_request]
)
# Optional: Add routing metadata if required by your flow
if routing_skill:
# This is a simplified representation. Real routing might require more complex objects
# depending on whether you are targeting a specific queue or skill group.
pass
try:
response = conversations_api.post_conversations(body=conversation_request)
print(f"Proactive conversation initiated: {response.conversation_id}")
return response.conversation_id
except ApiException as e:
print(f"Conversations API Error: {e.status} {e.reason}")
if e.body:
print(e.body)
return None
Step 3: Send the Initial Message (Optional but Recommended)
Initiating the conversation creates the session, but it does not automatically send a message. To engage the customer, you must send a message on behalf of the system or an agent. Since this is a proactive notification, you might want to send an automated welcome message.
Endpoint: POST /api/v2/conversations/{conversationId}/messages
Scope: conversation:webchat:message
from purecloud_platform_client.models import (
ConversationMessageCreateRequest,
MessageBody
)
def send_initial_message(api_client: ApiClient, conversation_id: str, message_text: str) -> bool:
"""
Sends the first message in the proactive conversation.
"""
conversations_api = ConversationsApi(api_client)
message_body = MessageBody(
text=message_text
)
# The sender is typically the system or an agent.
# For proactive, we often use a system-level identity or a specific agent if assigned.
# If no agent is assigned yet, sending as a system message might be limited.
# A common pattern is to assign an agent first, or send as a 'system' if allowed.
# Here we assume a basic text message.
message_request = ConversationMessageCreateRequest(
body=message_body,
type="text"
)
try:
# Note: The participant ID of the sender is often required.
# If sending as a system, this might be handled differently.
# For simplicity, we assume the conversation has a participant context.
conversations_api.post_conversations_messages(
conversation_id=conversation_id,
body=message_request
)
return True
except ApiException as e:
print(f"Message Send Error: {e.status} {e.reason}")
return False
Complete Working Example
This script combines the steps into a single executable module. It loads credentials, finds a customer, initiates a proactive chat, and sends a message.
import os
import sys
from dotenv import load_dotenv
from purecloud_platform_client import ApiClient, Configuration, AnalyticsApi, ConversationsApi
from purecloud_platform_client.rest import ApiException
from purecloud_platform_client.models import (
ConversationDetailsQueryRequest,
ConversationDetailsQueryFilter,
ConversationDetailsQueryFilterEntity,
ConversationDetailsQueryFilterField,
ConversationCreateRequest,
ConversationParticipantRequest,
ParticipantIdentity,
ConversationMessageCreateRequest,
MessageBody
)
def load_config():
load_dotenv()
config = Configuration(
client_id=os.getenv("GENESYS_CLOUD_CLIENT_ID"),
client_secret=os.getenv("GENESYS_CLOUD_CLIENT_SECRET"),
region=os.getenv("GENESYS_CLOUD_REGION", "us-east-1")
)
return ApiClient(configuration=config)
def find_customer(api_client: ApiClient, email: str):
analytics_api = AnalyticsApi(api_client)
email_filter = ConversationDetailsQueryFilter(
field=ConversationDetailsQueryFilterField("participants.email"),
operator="eq",
value=email
)
entity_filter = ConversationDetailsQueryFilterEntity(
field="type",
operator="eq",
value="webchat"
)
query = ConversationDetailsQueryRequest(
filters=[email_filter, entity_filter],
size=1,
sort_by=[{"field": "created_time", "order": "desc"}],
interval="PT1H",
from_time="2020-01-01T00:00:00Z",
to_time="2025-12-31T23:59:59Z"
)
try:
resp = analytics_api.post_anversations_details_query(body=query)
if resp.entities:
return resp.entities[0]
return None
except ApiException as e:
print(f"Error finding customer: {e}")
return None
def main():
customer_email = "customer@example.com"
welcome_message = "Hello! We noticed you visited our site. How can we help?"
api_client = load_config()
# Step 1: Find Customer
print(f"Searching for customer: {customer_email}")
customer_data = find_customer(api_client, customer_email)
if not customer_data:
print("Customer not found in historical web chats. Skipping.")
return
print(f"Customer found. Last conversation ID: {customer_data.conversation_id}")
# Step 2: Initiate Proactive Chat
print("Initiating proactive web chat...")
conversations_api = ConversationsApi(api_client)
identity = ParticipantIdentity(email=customer_email)
participant = ConversationParticipantRequest(identity=identity, type="customer")
req = ConversationCreateRequest(
type="webchat",
initiation_mode="proactive",
participants=[participant]
)
try:
new_conversation = conversations_api.post_conversations(body=req)
conv_id = new_conversation.conversation_id
print(f"Proactive conversation started: {conv_id}")
# Step 3: Send Message
print(f"Sending message: {welcome_message}")
msg_body = MessageBody(text=welcome_message)
msg_req = ConversationMessageCreateRequest(body=msg_body, type="text")
# Note: Sending a message in a proactive chat often requires an agent to be assigned
# or using a specific system identity. This may fail if no routing has occurred.
# For a true proactive notification, you might use the Notification API instead
# if Web Chat is not active on the client side.
conversations_api.post_conversations_messages(conversation_id=conv_id, body=msg_req)
print("Message sent successfully.")
except ApiException as e:
print(f"Failed to initiate or message: {e.status} {e.reason}")
if e.body:
print(e.body)
if __name__ == "__main__":
main()
Common Errors & Debugging
Error: 403 Forbidden
- Cause: The OAuth token lacks the required scope.
- Fix: Ensure
conversation:webchat:initiateandanalytics:query:readare added to your OAuth client’s scopes in the Genesys Cloud Admin console. - Code Check: Verify
Configurationinitialization includes the correct client ID and secret.
Error: 400 Bad Request - “Initiation mode proactive requires a target queue or skill”
- Cause: Proactive web chats often require a routing context to determine where the conversation should go if the customer responds.
- Fix: Add a
routingobject to theConversationCreateRequestspecifying a queue ID or skill group ID. - Code Fix:
from purecloud_platform_client.models import ConversationRoutingMetadata # ... routing_meta = ConversationRoutingMetadata( queue_id="your_queue_id" ) conversation_request.routing = routing_meta
Error: 409 Conflict - “Customer already has an active session”
- Cause: The customer currently has an open web chat session in their browser.
- Fix: Check the
statusof existing conversations for this customer. Only initiate proactive chats if no active sessions exist. - Debugging: Use the
find_customerfunction to check thestatusfield of the returned conversation entity. If status isactive, do not initiate a new one.
Error: 429 Too Many Requests
- Cause: Hitting API rate limits.
- Fix: Implement exponential backoff in your API calls. The Genesys Cloud Python SDK does not automatically retry 429s, so you must handle this in your wrapper code.
- Code Fix: Use a library like
tenacityor write a simple retry loop.