Define Genesys Cloud Queues with Skills Using Terraform CX as Code
What You Will Build
- You will provision a Genesys Cloud queue with specific skills, routing strategies, and member assignments using Infrastructure as Code.
- This tutorial uses the
genesyscloudTerraform provider (CX as Code) to manage queue resources declaratively. - The implementation covers Terraform HCL syntax, provider authentication, and state management for production-grade deployments.
Prerequisites
- Terraform Version: 1.5+
- Genesys Cloud Provider: v1.100.0+
- Genesys Cloud Environment: A tenant with appropriate permissions to create queues and assign skills.
- Required Permissions:
queue:createorqueue:editrouting:skillgroup:createorrouting:skillgroup:edit(if creating skills dynamically)routing:skill:createorrouting:skill:edit
- Authentication: Service Account credentials (Client ID and Client Secret) or Personal Access Token.
- External Dependencies: None beyond Terraform and the provider plugin.
Authentication Setup
The Genesys Cloud Terraform provider supports multiple authentication methods. For CI/CD pipelines and production environments, using a Service Account via environment variables is the standard approach. This avoids storing secrets in code.
You must set the following environment variables before running terraform init or terraform apply:
# Linux/MacOS
export GENESYS_CLOUD_REGION="mypurecloud.com"
export GENESYS_CLOUD_CLIENT_ID="your-client-id"
export GENESYS_CLOUD_CLIENT_SECRET="your-client-secret"
# Windows PowerShell
$env:GENESYS_CLOUD_REGION="mypurecloud.com"
$env:GENESYS_CLOUD_CLIENT_ID="your-client-id"
$env:GENESYS_CLOUD_CLIENT_SECRET="your-client-secret"
If you are testing locally with a Personal Access Token, you can use:
export GENESYS_CLOUD_TOKEN_TYPE="personal"
export GENESYS_CLOUD_TOKEN="your-personal-access-token"
The provider configuration in main.tf is minimal when environment variables are used. The provider automatically detects the credentials.
terraform {
required_providers {
genesyscloud = {
source = "genesys/cloud"
version = "~> 1.100.0"
}
}
}
provider "genesyscloud" {
# No explicit credentials needed if env vars are set.
# The provider will auto-detect from GENESYS_CLOUD_* variables.
}
Implementation
Step 1: Define Skills and Skill Groups
Queues in Genesys Cloud do not hold skills directly; they reference Skill Groups. Skills are defined at the global tenant level or within specific Skill Groups. To ensure your queue works correctly, you must first define the skills that agents will be assigned to.
In this example, we create a skill called billing_support and assign it to a Skill Group.
# Define a global skill
resource "genesyscloud_routing_skill" "billing_support" {
name = "Billing Support"
description = "Skill for handling billing inquiries"
}
# Define a Skill Group (optional but recommended for organization)
resource "genesyscloud_routing_skillgroup" "finance_group" {
name = "Finance Skills"
description = "Group containing all finance-related skills"
# Assign the skill to this group
skills {
skill_id = genesyscloud_routing_skill.billing_support.id
name = genesyscloud_routing_skill.billing_support.name
}
}
Key Parameters:
name: The display name of the skill. This is what appears in the admin console.description: Optional metadata for documentation.skillsblock insiderouting_skillgroup: Links the global skill to the group.
Error Handling:
If the skill name already exists, Terraform will fail with a 409 Conflict error. To prevent this during iterative development, use the genesyscloud_routing_skill data source to look up existing skills if they might already exist, or ensure your naming convention is unique.
Step 2: Configure the Queue Resource
The core resource is genesyscloud_routing_queue. This resource maps directly to the /api/v2/routing/queues endpoint. You must define the queue name, description, and crucially, the skills that determine who can answer calls routed to this queue.
resource "genesyscloud_routing_queue" "billing_queue" {
name = "Billing Support Queue"
description = "Queue for inbound billing calls"
enabled = true
# Define the skills required to answer this queue
skills {
skill_id = genesyscloud_routing_skill.billing_support.id
level = 1 # Skill level required (1-5)
}
# Routing strategy
routing_strategy = "longest_idle"
# Wrap-up codes (optional)
wrap_up_code_required = false
# Member configuration
members {
# Reference an existing user or create one
# For this example, we assume a user ID is known or looked up
user_id = var.support_agent_user_id
skills {
skill_id = genesyscloud_routing_skill.billing_support.id
level = 5 # Agent's proficiency level
}
}
# Outbound campaign settings (if applicable)
outbound {
enabled = false
}
# Small talk configuration (optional)
small_talk {
enabled = false
}
# Hold music
hold_music = "default"
}
Key Parameters Explained:
skills: A list of objects. Each object containsskill_id(the UUID of the skill) andlevel(1-5). The queue requires agents to have at least this skill level to be routed to.routing_strategy: Determines how the next available agent is selected. Common values:longest_idle,equalize,fewest_conversations,skill_only.members: A list of agents assigned to the queue. Each member entry can specify their skill levels for the skills defined in the queue.wrap_up_code_required: Iftrue, agents must select a wrap-up code before taking the next call.
Non-Obvious Detail:
The members block in genesyscloud_routing_queue does not create the user. It only assigns the user to the queue. If the user_id does not exist, the apply will fail. You must either create the user first using genesyscloud_user or reference an existing user via a data source.
Step 3: Lookup Existing Users (Data Source)
Hardcoding user IDs is fragile. Use the genesyscloud_user data source to dynamically find the user ID based on their email or name.
data "genesyscloud_user" "support_agent" {
email = "agent@example.com"
}
Then reference it in the queue:
resource "genesyscloud_routing_queue" "billing_queue" {
# ... previous configuration ...
members {
user_id = data.genesyscloud_user.support_agent.id
skills {
skill_id = genesyscloud_routing_skill.billing_support.id
level = 5
}
}
}
Edge Case:
If multiple users share the same email (unlikely) or name, the data source may return multiple results. Ensure the lookup criteria are unique. If no user is found, Terraform will fail with a “Resource not found” error.
Step 4: Add Queue Members via Dedicated Resource (Alternative Pattern)
For large-scale deployments, managing members inside the queue resource can lead to large state files and complex diffs. A better pattern is to use the genesyscloud_routing_queue_member resource for each member. This allows independent management of queue membership.
# Define the queue without members first
resource "genesyscloud_routing_queue" "billing_queue" {
name = "Billing Support Queue"
description = "Queue for inbound billing calls"
enabled = true
skills {
skill_id = genesyscloud_routing_skill.billing_support.id
level = 1
}
routing_strategy = "longest_idle"
wrap_up_code_required = false
hold_music = "default"
}
# Add members separately
resource "genesyscloud_routing_queue_member" "agent_assignment" {
queue_id = genesyscloud_routing_queue.billing_queue.id
user_id = data.genesyscloud_user.support_agent.id
skills {
skill_id = genesyscloud_routing_skill.billing_support.id
level = 5
}
}
Why Use This Pattern?
- Modularity: You can add/remove agents without touching the queue definition.
- Scalability: Terraform handles the member addition as separate API calls, reducing the risk of partial failures.
- Clarity: The queue resource focuses on routing logic, while member resources focus on staffing.
Complete Working Example
Below is a complete main.tf file that creates a skill, a queue, looks up a user, and assigns them to the queue.
terraform {
required_providers {
genesyscloud = {
source = "genesys/cloud"
version = "~> 1.100.0"
}
}
}
provider "genesyscloud" {
# Authentication handled via environment variables
}
# Variable for user email
variable "support_agent_email" {
description = "Email of the support agent to assign to the queue"
type = string
default = "agent@example.com"
}
# 1. Create the Skill
resource "genesyscloud_routing_skill" "billing_support" {
name = "Billing Support"
description = "Skill for handling billing inquiries"
}
# 2. Lookup the User
data "genesyscloud_user" "support_agent" {
email = var.support_agent_email
}
# 3. Create the Queue
resource "genesyscloud_routing_queue" "billing_queue" {
name = "Billing Support Queue"
description = "Queue for inbound billing calls"
enabled = true
# Skills required for the queue
skills {
skill_id = genesyscloud_routing_skill.billing_support.id
level = 1
}
# Routing configuration
routing_strategy = "longest_idle"
wrap_up_code_required = false
hold_music = "default"
# Outbound settings
outbound {
enabled = false
}
}
# 4. Assign the User to the Queue
resource "genesyscloud_routing_queue_member" "agent_assignment" {
queue_id = genesyscloud_routing_queue.billing_queue.id
user_id = data.genesyscloud_user.support_agent.id
# Agent's skill level for this queue
skills {
skill_id = genesyscloud_routing_skill.billing_support.id
level = 5
}
}
# Output the Queue ID for verification
output "queue_id" {
value = genesyscloud_routing_queue.billing_queue.id
}
output "queue_name" {
value = genesyscloud_routing_queue.billing_queue.name
}
How to Run:
- Save the code to
main.tf. - Set your environment variables (
GENESYS_CLOUD_REGION,GENESYS_CLOUD_CLIENT_ID,GENESYS_CLOUD_CLIENT_SECRET). - Run
terraform initto download the provider. - Run
terraform planto preview the changes. - Run
terraform applyto create the resources.
Common Errors & Debugging
Error: 409 Conflict (Resource Already Exists)
What causes it:
You attempted to create a skill or queue with a name that already exists in your Genesys Cloud tenant. Genesys Cloud enforces unique names for skills and queues within certain scopes.
How to fix it:
- Check the existing resources in the Genesys Cloud Admin Console.
- Update the
namein your Terraform code to be unique. - Alternatively, use the
genesyscloud_routing_skilldata source to import the existing resource into your Terraform state if you want to manage it via code.
# Import existing skill
import {
to = genesyscloud_routing_skill.existing_billing
id = "existing-skill-uuid"
}
resource "genesyscloud_routing_skill" "existing_billing" {
name = "Billing Support" # Must match existing name
}
Error: 404 Not Found (User Not Found)
What causes it:
The genesyscloud_user data source could not find a user with the specified email. This usually happens if the email is misspelled or the user does not exist in the tenant.
How to fix it:
- Verify the email address in the Genesys Cloud Admin Console.
- Ensure the user is not deactivated.
- If the user does not exist, create them using
genesyscloud_userresource before referencing them.
Error: 400 Bad Request (Invalid Skill Level)
What causes it:
The level parameter in the skills block is outside the valid range (1-5).
How to fix it:
Ensure all level values in skills blocks are integers between 1 and 5.
# Invalid
skills {
skill_id = genesyscloud_routing_skill.billing_support.id
level = 10 # Error: Level must be 1-5
}
# Valid
skills {
skill_id = genesyscloud_routing_skill.billing_support.id
level = 5
}
Error: 429 Too Many Requests
What causes it:
Genesys Cloud API rate limits have been exceeded. This can happen during large-scale deployments with many resources.
How to fix it:
The Terraform provider includes built-in retry logic for 429 errors. However, if you are creating many resources, consider adding a delay in your Terraform configuration or breaking the deployment into smaller batches.