How to Set Wrap-Up Codes Programmatically After an Interaction Ends
What You Will Build
- This tutorial demonstrates how to programmatically apply a wrap-up code to a completed conversation in Genesys Cloud.
- It utilizes the Genesys Cloud Messaging API (
/api/v2/conversations/messaging) and the Conversations API (/api/v2/conversations). - The primary implementation uses Python with the official
genesyscloudSDK, with supplementary JavaScript examples for REST API integration.
Prerequisites
Authentication & Scopes
- OAuth Client Type: Public or Confidential Client. A Confidential Client is recommended for server-to-server integrations.
- Required Scopes:
conversation:read(to retrieve conversation details)conversation:write(to update the wrap-up code)user:read(optional, if resolving user IDs for agents)
- Environment: A Genesys Cloud Organization with at least one active Messaging queue and configured Wrap-Up Codes.
SDK & Dependencies
- Python:
genesyscloud>=2.16.0 - Node.js:
axios(for REST examples) - Runtime: Python 3.9+ or Node.js 18+
Installation
# Python
pip install genesyscloud
# Node.js
npm install axios
Authentication Setup
Genesys Cloud uses OAuth 2.0 for authentication. For programmatic access, the Client Credentials flow is the standard approach. This flow exchanges a client ID and secret for an access token.
Python SDK Authentication
The genesyscloud SDK provides a PlatformClient class that handles token acquisition and refresh automatically. You must initialize the client with your environment base URL, client ID, and client secret.
from genesyscloud.platform.client import PlatformClient
def get_platform_client(client_id: str, client_secret: str, environment: str = "mypurecloud.com") -> PlatformClient:
"""
Initializes and returns an authenticated Genesys Cloud PlatformClient.
"""
# Construct the base URL
base_url = f"https://{environment}"
# Create the client
client = PlatformClient(base_url=base_url)
# Authenticate using Client Credentials
client.login(client_id=client_id, client_secret=client_secret)
return client
# Usage
# client = get_platform_client("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")
JavaScript (REST) Authentication
For environments where the full SDK is not desired, use Axios to manage the token lifecycle. Note that tokens expire after a set duration (typically 1 hour). A production implementation should implement token caching.
const axios = require('axios');
const GENESYS_BASE_URL = 'https://api.mypurecloud.com';
const CLIENT_ID = 'YOUR_CLIENT_ID';
const CLIENT_SECRET = 'YOUR_CLIENT_SECRET';
async function getAccessToken() {
const response = await axios.post(`${GENESYS_BASE_URL}/oauth/token`, {
grant_type: 'client_credentials',
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET
});
if (response.data.access_token) {
return response.data.access_token;
}
throw new Error('Failed to retrieve access token');
}
// Usage
// const token = await getAccessToken();
Implementation
Setting a wrap-up code is not a single atomic action in all contexts. It generally involves two distinct steps:
- Identify the Conversation: Locate the specific conversation ID and verify its state is
completedorclosed. - Apply the Wrap-Up: Send a
PATCHrequest to the conversation endpoint with the wrap-up code ID.
Step 1: Retrieve Available Wrap-Up Codes
Before setting a wrap-up, you must know the valid wrapUpCodeId values. Wrap-up codes are organizational or queue-specific. If you are applying a wrap-up to a Messaging conversation, you typically need the ID of the code associated with the queue the agent was assigned to, or a global code.
We will fetch the list of wrap-up codes to find the correct ID.
Python SDK Example
from genesyscloud.platform.client import PlatformClient
def get_wrap_up_codes(client: PlatformClient) -> list:
"""
Retrieves all available wrap-up codes for the organization.
"""
try:
# Use the analytics or conversations API to list wrap-up codes
# Note: The SDK method for listing wrap-up codes is often under
# client.conversations_api or client.analytics_api depending on version.
# In recent SDK versions, it is: client.conversations_api.get_conversations_wrapupcodes()
response = client.conversations_api.get_conversations_wrapupcodes()
if response and response.body:
return response.body.entities
else:
print("No wrap-up codes found.")
return []
except Exception as e:
print(f"Error retrieving wrap-up codes: {e}")
return []
# Example usage to find a specific code by name
def find_wrap_up_code_by_name(client: PlatformClient, target_name: str) -> str | None:
codes = get_wrap_up_codes(client)
for code in codes:
if code.name == target_name:
return code.id
return None
Key Parameter Explanation
get_conversations_wrapupcodes(): Returns aWrapUpCodeEntityListing.entities: A list ofWrapUpCodeobjects. Each object containsid,name,description, andenabled.
Step 2: Locate the Completed Conversation
You must target a conversation that has already ended. In Genesys Cloud, a conversation is eligible for wrap-up when its state is completed. You can search for conversations using the GET /api/v2/conversations endpoint with query parameters.
Python SDK Example
from genesyscloud.platform.client import PlatformClient
from genesyscloud.conversations.api.conversations_api import ConversationsApi
def find_completed_conversation(client: PlatformClient, participant_id: str) -> str | None:
"""
Finds the most recent completed conversation for a specific participant.
Args:
client: Authenticated PlatformClient
participant_id: The ID of the user or external user involved in the chat.
Returns:
The conversation ID string, or None if not found.
"""
try:
# Query parameters
# state=completed ensures we only get finished conversations
# type=messaging filters for chat/messaging interactions
# participantIds filters by the specific user
response = client.conversations_api.get_conversations(
state="completed",
type="messaging",
participant_ids=[participant_id],
sort_by="lastUpdatedTime",
sort_order="desc",
page_size=1
)
if response.body and response.body.entities and len(response.body.entities) > 0:
return response.body.entities[0].id
else:
print(f"No completed messaging conversation found for participant {participant_id}")
return None
except Exception as e:
print(f"Error searching for conversations: {e}")
return None
Important Constraints
- State Check: You cannot set a wrap-up code on a conversation with state
active,ringing, orqueued. The API will return a409 Conflictif the conversation is not in a terminal state. - Participant ID: Ensure the
participant_idcorresponds to an entry in theparticipantsarray of the conversation object. For external users, this is often theexternalIdor theidof the participant object within the conversation.
Step 3: Apply the Wrap-Up Code
Once you have the conversationId and the wrapUpCodeId, you send a PATCH request to /api/v2/conversations/{conversationId}. The body must include the wrapUpCodeId field.
Python SDK Example
from genesyscloud.platform.client import PlatformClient
from genesyscloud.model.wrap_up_code import WrapUpCode
def set_wrap_up_code(client: PlatformClient, conversation_id: str, wrap_up_code_id: str) -> bool:
"""
Applies a wrap-up code to a completed conversation.
Args:
client: Authenticated PlatformClient
conversation_id: The ID of the conversation
wrap_up_code_id: The ID of the wrap-up code to apply
Returns:
True if successful, False otherwise.
"""
try:
# Construct the body
# The SDK may require a specific model class.
# For PATCH, we often just need the ID in a dict or a specific model.
# In many SDK versions, the body is a dict or a Conversation object.
body = {
"wrapUpCodeId": wrap_up_code_id
}
# Execute the PATCH request
# Note: The method name in the SDK is typically
# patch_conversations_conversation
response = client.conversations_api.patch_conversations_conversation(
conversation_id=conversation_id,
body=body
)
print(f"Wrap-up code applied successfully. Status Code: {response.status_code}")
return True
except Exception as e:
# Handle specific errors
if hasattr(e, 'status_code') and e.status_code == 409:
print("Conflict: Conversation is not in a state that allows wrap-up modification.")
elif hasattr(e, 'status_code') and e.status_code == 404:
print("Not Found: Conversation or Wrap-Up Code ID is invalid.")
else:
print(f"Error applying wrap-up code: {e}")
return False
JavaScript (REST) Example
const axios = require('axios');
async function setWrapUpCodeREST(token, conversationId, wrapUpCodeId) {
const url = `${GENESYS_BASE_URL}/api/v2/conversations/${conversationId}`;
try {
const response = await axios.patch(url, {
wrapUpCodeId: wrapUpCodeId
}, {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
console.log(`Wrap-up code applied. Status: ${response.status}`);
return true;
} catch (error) {
if (error.response) {
if (error.response.status === 409) {
console.error("Conflict: Conversation state does not allow wrap-up changes.");
} else if (error.response.status === 404) {
console.error("Not Found: Invalid Conversation or Wrap-Up Code ID.");
} else {
console.error(`Error: ${error.response.status} - ${error.response.data}`);
}
} else {
console.error("Network Error:", error.message);
}
return false;
}
}
Step 4: Verification
After setting the wrap-up, it is good practice to verify the change. Retrieve the conversation again and check the wrapUpCodeId field in the response.
def verify_wrap_up(client: PlatformClient, conversation_id: str) -> str | None:
"""
Retrieves the conversation and returns the applied wrap-up code ID.
"""
try:
response = client.conversations_api.get_conversations_conversation(
conversation_id=conversation_id
)
if response.body:
return response.body.wrap_up_code_id
return None
except Exception as e:
print(f"Error verifying wrap-up: {e}")
return None
Complete Working Example
This Python script combines all steps: authenticates, finds a wrap-up code by name, finds a recent completed conversation for a user, applies the code, and verifies the result.
import sys
import os
from genesyscloud.platform.client import PlatformClient
# Configuration
CLIENT_ID = os.getenv("GENESYS_CLIENT_ID")
CLIENT_SECRET = os.getenv("GENESYS_CLIENT_SECRET")
ENVIRONMENT = os.getenv("GENESYS_ENV", "mypurecloud.com")
PARTICIPANT_ID = os.getenv("GENESYS_PARTICIPANT_ID") # ID of the user/external user
TARGET_WRAP_UP_NAME = os.getenv("TARGET_WRAP_UP_NAME", "General")
def main():
if not CLIENT_ID or not CLIENT_SECRET or not PARTICIPANT_ID:
print("Error: Missing required environment variables.")
print("Set: GENESYS_CLIENT_ID, GENESYS_CLIENT_SECRET, GENESYS_PARTICIPANT_ID")
sys.exit(1)
# 1. Initialize Client
print("Initializing Genesys Cloud Client...")
client = PlatformClient(base_url=f"https://{ENVIRONMENT}")
client.login(client_id=CLIENT_ID, client_secret=CLIENT_SECRET)
# 2. Find Wrap-Up Code ID
print(f"Searching for wrap-up code: '{TARGET_WRAP_UP_NAME}'")
wrap_up_code_id = find_wrap_up_code_by_name(client, TARGET_WRAP_UP_NAME)
if not wrap_up_code_id:
print(f"Error: Wrap-up code '{TARGET_WRAP_UP_NAME}' not found.")
sys.exit(1)
print(f"Found Wrap-Up Code ID: {wrap_up_code_id}")
# 3. Find Completed Conversation
print(f"Searching for completed conversation for participant: {PARTICIPANT_ID}")
conversation_id = find_completed_conversation(client, PARTICIPANT_ID)
if not conversation_id:
print("Error: No completed conversation found.")
sys.exit(1)
print(f"Found Conversation ID: {conversation_id}")
# 4. Apply Wrap-Up Code
print("Applying wrap-up code...")
success = set_wrap_up_code(client, conversation_id, wrap_up_code_id)
if not success:
print("Failed to apply wrap-up code.")
sys.exit(1)
# 5. Verify
print("Verifying wrap-up code...")
applied_id = verify_wrap_up(client, conversation_id)
if applied_id == wrap_up_code_id:
print("Success: Wrap-up code applied and verified.")
else:
print(f"Warning: Verification mismatch. Expected {wrap_up_code_id}, got {applied_id}")
# Helper functions from previous steps included here for completeness
def find_wrap_up_code_by_name(client, target_name):
try:
response = client.conversations_api.get_conversations_wrapupcodes()
if response and response.body:
for code in response.body.entities:
if code.name == target_name:
return code.id
except Exception as e:
print(f"Error listing wrap-up codes: {e}")
return None
def find_completed_conversation(client, participant_id):
try:
response = client.conversations_api.get_conversations(
state="completed",
type="messaging",
participant_ids=[participant_id],
sort_by="lastUpdatedTime",
sort_order="desc",
page_size=1
)
if response.body and response.body.entities and len(response.body.entities) > 0:
return response.body.entities[0].id
except Exception as e:
print(f"Error searching conversations: {e}")
return None
def set_wrap_up_code(client, conversation_id, wrap_up_code_id):
try:
body = {"wrapUpCodeId": wrap_up_code_id}
client.conversations_api.patch_conversations_conversation(
conversation_id=conversation_id,
body=body
)
return True
except Exception as e:
print(f"Error setting wrap-up: {e}")
return False
def verify_wrap_up(client, conversation_id):
try:
response = client.conversations_api.get_conversations_conversation(
conversation_id=conversation_id
)
if response.body:
return response.body.wrap_up_code_id
except Exception as e:
print(f"Error verifying: {e}")
return None
if __name__ == "__main__":
main()
Common Errors & Debugging
Error: 409 Conflict
Cause: The conversation is not in a state that allows modification. Specifically, the conversation state is not completed.
Fix:
- Check the conversation state using
GET /api/v2/conversations/{id}. - Ensure the conversation has ended. For messaging, this means the agent has closed the session.
- If the conversation is still
active, wait for it to close or trigger the close action programmatically via the messaging API before attempting to set the wrap-up.
# Debugging code
response = client.conversations_api.get_conversations_conversation(conversation_id)
print(f"Current State: {response.body.state}")
if response.body.state != "completed":
print("Conversation is not completed. Cannot set wrap-up.")
Error: 404 Not Found
Cause: The conversationId or wrapUpCodeId is invalid.
Fix:
- Verify the
conversationIdexists and belongs to the organization. - Verify the
wrapUpCodeIdexists and is enabled. - Check for typos in the IDs.
Error: 403 Forbidden
Cause: The OAuth token lacks the conversation:write scope.
Fix:
- Update the OAuth Client in the Genesys Cloud Admin Console.
- Add the
conversation:writescope. - Re-generate the token or refresh the authentication session.
Error: 429 Too Many Requests
Cause: The API rate limit has been exceeded.
Fix:
- Implement exponential backoff in your retry logic.
- Check the
Retry-Afterheader in the response.
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_code') and e.status_code == 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")