Configure Genesys Cloud Webhooks for Slack Notifications on Queue SLA Breaches
What You Will Build
- Create a Genesys Cloud Webhook resource that triggers when a queue conversation breaches a defined Service Level Agreement (SLA) threshold.
- Use the Genesys Cloud Webhooks API (
/api/v2/webhooks) via the Python SDK to define the event subscription, HTTP endpoint, and authentication headers required by Slack. - Implement a Python script that programmatically registers this webhook, validates the configuration, and handles common authentication and validation errors.
Prerequisites
- Genesys Cloud Account: An account with
admin:webhookandadmin:queuepermissions. You must have access to a specific Queue ID to reference in the webhook configuration. - Slack App: A Slack application with an Incoming Webhook URL or a custom endpoint that accepts JSON payloads. For this tutorial, we assume you have a valid Slack Incoming Webhook URL (e.g.,
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX). - Python Environment: Python 3.8 or higher.
- Dependencies:
genesyscloud: The official Genesys Cloud Python SDK.requests: For handling HTTP interactions if not using the SDK exclusively for debugging.os: For environment variable management.
Install the required packages:
pip install genesyscloud requests
Authentication Setup
Genesys Cloud uses OAuth 2.0 for API authentication. You must generate a Client ID and Client Secret in the Genesys Cloud Admin Console under Integrations > OAuth.
- Navigate to Admin > Integrations > OAuth.
- Click Create Client.
- Set the Client Name (e.g., “Slack-Webhook-Automation”).
- Select Confidential Client as the type.
- Add the following scopes:
admin:webhookadmin:queue
- Save and copy the Client ID and Client Secret.
Store these credentials in environment variables to avoid hardcoding secrets in your script.
export GENESYS_CLOUD_REGION="mypurecloud.com"
export GENESYS_CLOUD_CLIENT_ID="your_client_id"
export GENESYS_CLOUD_CLIENT_SECRET="your_client_secret"
export GENESYS_CLOUD_ORGANIZATION_ID="your_org_id"
Implementation
Step 1: Initialize the Genesys Cloud API Client
The first step is to initialize the PureCloudPlatformClientV2 client. This object handles the OAuth token exchange, caching, and refresh logic automatically. It also sets the base URL based on the region.
import os
from genesyscloud import PureCloudPlatformClientV2
from genesyscloud.model import WebhookEntity, WebhookEvent, WebhookHttpEntity
def get_genesys_client():
"""
Initializes and returns the Genesys Cloud API client.
"""
# Retrieve credentials from environment variables
client_id = os.environ.get("GENESYS_CLOUD_CLIENT_ID")
client_secret = os.environ.get("GENESYS_CLOUD_CLIENT_SECRET")
org_id = os.environ.get("GENESYS_CLOUD_ORGANIZATION_ID")
region = os.environ.get("GENESYS_CLOUD_REGION", "mypurecloud.com")
if not client_id or not client_secret or not org_id:
raise ValueError("Missing required environment variables: GENESYS_CLOUD_CLIENT_ID, GENESYS_CLOUD_CLIENT_SECRET, GENESYS_CLOUD_ORGANIZATION_ID")
# Initialize the client
client = PureCloudPlatformClientV2()
# Set the region
client.set_region(region)
# Configure OAuth2 authentication
client.set_client_credentials(client_id, client_secret, org_id)
return client
# Initialize the client globally or within a function scope
genesys_client = get_genesys_client()
Error Handling: If the credentials are invalid, the SDK will raise an ApiException with a 401 status code when the first API call is made. Ensure your environment variables are correctly set before proceeding.
Step 2: Define the Webhook Event and Configuration
Genesys Cloud webhooks are triggered by specific events. For SLA breaches, the relevant event is routing:queue:conversation:sla:breached. This event fires when a conversation in a queue exceeds the configured SLA threshold.
You must define the webhook entity with the following components:
- Name: A descriptive name for the webhook.
- Event: The specific Genesys Cloud event to subscribe to.
- HttpEntity: The HTTP endpoint configuration, including the URL, headers, and body format.
- Enabled: Set to
trueto activate the webhook.
from genesyscloud.model import WebhookEntity, WebhookEvent, WebhookHttpEntity
def create_slack_webhook_config(queue_id: str, slack_webhook_url: str) -> WebhookEntity:
"""
Creates the WebhookEntity configuration for Slack notifications on SLA breach.
Args:
queue_id (str): The ID of the Genesys Cloud queue to monitor.
slack_webhook_url (str): The Slack Incoming Webhook URL.
Returns:
WebhookEntity: The configured webhook entity.
"""
# Define the event
event = WebhookEvent(
name="routing:queue:conversation:sla:breached"
)
# Define the HTTP entity for Slack
# Slack Incoming Webhooks expect a JSON payload with a 'text' field
http_entity = WebhookHttpEntity(
url=slack_webhook_url,
method="POST",
headers={
"Content-Type": "application/json"
},
# The body template uses Handlebars-like syntax to reference event data
# Note: Genesys Cloud webhooks support a specific template syntax.
# For simplicity, we will send the raw event payload and let Slack parse it,
# or use a basic template if supported by your webhook version.
# In this example, we send the entire event context.
body="{"
"\"text\": \"*SLA Breach Alert*: Queue {{queue.name}} has a conversation that breached SLA. "
"Wait Time: {{waitTime}}s. "
"Conversation ID: {{conversationId}}\""
"}"
)
# Define the main webhook entity
webhook = WebhookEntity(
name="Slack SLA Breach Notification",
description="Sends a notification to Slack when a queue conversation breaches SLA.",
event=event,
http=http_entity,
enabled=True,
# Optional: Filter by specific queue to reduce noise
# This is a critical step to ensure you only receive alerts for the intended queue.
# The 'filter' field is not a standard top-level field in WebhookEntity,
# but rather part of the event subscription logic.
# However, for simple webhooks, we rely on the event payload to contain queue info.
# To strictly filter, we might need to use a more advanced integration or
# handle filtering in the receiving endpoint.
# For this tutorial, we assume the webhook is global but the Slack message
# will only be useful if we filter the payload or use a specific queue ID in the name.
# A better approach is to use the 'routing:queue:conversation:sla:breached' event
# which inherently ties to a queue. We will not filter by queue ID in the API
# because the event itself is per-queue. If you want to listen to ALL queues,
# this webhook will fire for all. If you want to listen to one, you might need
# to create separate webhooks or handle filtering in the HTTP handler.
# For this example, we create a global listener.
)
return webhook
Important Note on Filtering: The routing:queue:conversation:sla:breached event is emitted for every queue in your organization. If you have many queues, this will generate significant traffic. To filter, you can either:
- Create multiple webhooks, one per queue (not recommended for scale).
- Handle filtering in your Slack endpoint (recommended).
- Use the
WebhookFilterAPI if available in your SDK version (check documentation forfilterproperty inWebhookEntity). As of recent SDK versions, theWebhookEntitydoes not have a directqueueIdfilter property. Instead, you filter based on the event payload in your receiver.
Step 3: Create the Webhook via API
Now, use the WebhooksApi to create the webhook. This step requires the admin:webhook scope.
from genesyscloud import WebhooksApi
from genesyscloud.exceptions import ApiException
def create_webhook(client: PureCloudPlatformClientV2, webhook_entity: WebhookEntity):
"""
Creates a webhook in Genesys Cloud.
Args:
client (PureCloudPlatformClientV2): The initialized Genesys Cloud client.
webhook_entity (WebhookEntity): The webhook configuration.
Returns:
WebhookEntity: The created webhook entity with ID and metadata.
"""
webhooks_api = WebhooksApi(client)
try:
# Post the webhook entity
created_webhook = webhooks_api.post_webhooks(body=webhook_entity)
print(f"Webhook created successfully with ID: {created_webhook.id}")
return created_webhook
except ApiException as e:
print(f"Exception when calling WebhooksApi->post_webhooks: {e}")
if e.status == 400:
print("Bad Request: Check the webhook configuration for errors.")
elif e.status == 401:
print("Unauthorized: Check your OAuth credentials.")
elif e.status == 403:
print("Forbidden: Ensure you have the 'admin:webhook' scope.")
elif e.status == 409:
print("Conflict: A webhook with this name or configuration may already exist.")
raise e
# Example usage
queue_id = "your-queue-id-here"
slack_url = "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX"
webhook_config = create_slack_webhook_config(queue_id, slack_url)
created_webhook = create_webhook(genesys_client, webhook_config)
Expected Response: A successful creation returns a 201 Created status with the full WebhookEntity object, including the generated id, selfUri, and createdTimestamp.
Step 4: Validate the Webhook Configuration
After creation, it is good practice to verify the webhook is active and correctly configured. You can fetch the webhook by ID.
def get_webhook(client: PureCloudPlatformClientV2, webhook_id: str):
"""
Retrieves a webhook by ID to verify its configuration.
Args:
client (PureCloudPlatformClientV2): The initialized Genesys Cloud client.
webhook_id (str): The ID of the webhook to retrieve.
Returns:
WebhookEntity: The retrieved webhook entity.
"""
webhooks_api = WebhooksApi(client)
try:
webhook = webhooks_api.get_webhooks_webhook_id(webhook_id=webhook_id)
print(f"Webhook Name: {webhook.name}")
print(f"Webhook Status: {'Enabled' if webhook.enabled else 'Disabled'}")
print(f"Webhook Event: {webhook.event.name}")
return webhook
except ApiException as e:
print(f"Exception when calling WebhooksApi->get_webhooks_webhook_id: {e}")
raise e
# Verify the created webhook
if created_webhook:
verified_webhook = get_webhook(genesys_client, created_webhook.id)
Complete Working Example
Below is the complete, copy-pasteable Python script. Ensure you have set the environment variables as described in the Prerequisites section.
import os
import sys
from genesyscloud import PureCloudPlatformClientV2
from genesyscloud import WebhooksApi
from genesyscloud.model import WebhookEntity, WebhookEvent, WebhookHttpEntity
from genesyscloud.exceptions import ApiException
def get_genesys_client():
"""
Initializes and returns the Genesys Cloud API client.
"""
client_id = os.environ.get("GENESYS_CLOUD_CLIENT_ID")
client_secret = os.environ.get("GENESYS_CLOUD_CLIENT_SECRET")
org_id = os.environ.get("GENESYS_CLOUD_ORGANIZATION_ID")
region = os.environ.get("GENESYS_CLOUD_REGION", "mypurecloud.com")
if not client_id or not client_secret or not org_id:
raise ValueError("Missing required environment variables: GENESYS_CLOUD_CLIENT_ID, GENESYS_CLOUD_CLIENT_SECRET, GENESYS_CLOUD_ORGANIZATION_ID")
client = PureCloudPlatformClientV2()
client.set_region(region)
client.set_client_credentials(client_id, client_secret, org_id)
return client
def create_slack_webhook_config(slack_webhook_url: str) -> WebhookEntity:
"""
Creates the WebhookEntity configuration for Slack notifications on SLA breach.
"""
event = WebhookEvent(
name="routing:queue:conversation:sla:breached"
)
# Slack Incoming Webhooks expect a JSON payload.
# The body template uses Genesys Cloud's webhook templating syntax.
# Available variables depend on the event. For 'routing:queue:conversation:sla:breached',
# common variables include: queue.name, waitTime, conversationId, etc.
body_template = (
"{"
"\"text\": \"*SLA Breach Alert*\\n"
"Queue: {{queue.name}}\\n"
"Wait Time: {{waitTime}}s\\n"
"Conversation ID: {{conversationId}}\\n"
"Agent: {{agent.name}}\\n"
"Customer: {{customer.name}}\""
"}"
)
http_entity = WebhookHttpEntity(
url=slack_webhook_url,
method="POST",
headers={
"Content-Type": "application/json"
},
body=body_template
)
webhook = WebhookEntity(
name="Slack SLA Breach Notification",
description="Sends a notification to Slack when a queue conversation breaches SLA.",
event=event,
http=http_entity,
enabled=True
)
return webhook
def create_webhook(client: PureCloudPlatformClientV2, webhook_entity: WebhookEntity):
"""
Creates a webhook in Genesys Cloud.
"""
webhooks_api = WebhooksApi(client)
try:
created_webhook = webhooks_api.post_webhooks(body=webhook_entity)
print(f"Success: Webhook created with ID: {created_webhook.id}")
return created_webhook
except ApiException as e:
print(f"Error creating webhook: {e}")
if e.status == 409:
print("Note: A webhook with this name may already exist. Consider updating the name.")
sys.exit(1)
def main():
# Initialize Client
try:
genesys_client = get_genesys_client()
except ValueError as ve:
print(f"Configuration Error: {ve}")
sys.exit(1)
# Get Slack Webhook URL from environment or hardcode for testing
slack_url = os.environ.get("SLACK_WEBHOOK_URL")
if not slack_url:
print("Warning: SLACK_WEBHOOK_URL not set. Using placeholder.")
slack_url = "https://hooks.slack.com/services/PLACEHOLDER"
# Create Webhook Configuration
webhook_config = create_slack_webhook_config(slack_url)
# Create Webhook
created_webhook = create_webhook(genesys_client, webhook_config)
# Verify Webhook
if created_webhook:
webhooks_api = WebhooksApi(genesys_client)
try:
verified = webhooks_api.get_webhooks_webhook_id(webhook_id=created_webhook.id)
print(f"Verification: Webhook '{verified.name}' is {'enabled' if verified.enabled else 'disabled'}.")
except ApiException as e:
print(f"Verification Error: {e}")
if __name__ == "__main__":
main()
Common Errors & Debugging
Error: 400 Bad Request - Invalid Webhook Configuration
Cause: The webhook body template contains invalid syntax or references variables that do not exist in the event payload.
Fix: Validate the template syntax. Genesys Cloud webhooks use a Handlebars-like syntax. Ensure that variables like {{queue.name}} are valid for the routing:queue:conversation:sla:breached event. You can test the payload structure by checking the Event Playground in the Genesys Cloud Admin Console under Integrations > Webhooks > Event Playground.
Error: 401 Unauthorized
Cause: The OAuth token is invalid, expired, or missing the required scopes.
Fix: Verify that the GENESYS_CLOUD_CLIENT_ID and GENESYS_CLOUD_CLIENT_SECRET are correct. Ensure the OAuth client has the admin:webhook scope. The SDK handles token refresh, but if the client credentials are wrong, the initial token exchange will fail.
Error: 403 Forbidden
Cause: The authenticated user lacks the admin:webhook permission.
Fix: Check the role assignments for the OAuth client or the user associated with the credentials. In Genesys Cloud, permissions are granted via roles. Ensure the role assigned to the OAuth client includes “Webhook Management”.
Error: 409 Conflict
Cause: A webhook with the same name and event combination already exists.
Fix: Genesys Cloud enforces uniqueness on webhook names within an organization. Either update the name of the new webhook or delete the existing one before creating a new one. You can list existing webhooks using webhooks_api.get_webhooks() to check for duplicates.