Define Genesys Cloud Queues with Skills in Terraform Using CX as Code

Define Genesys Cloud Queues with Skills in Terraform Using CX as Code

What You Will Build

  • You will create a Genesys Cloud queue with specific skills, routing strategies, and wrap-up codes using Terraform.
  • You will use the mikeschinkel/genesys-cloud Terraform provider (commonly referred to in the community as the CX as Code provider) to manage infrastructure as code.
  • You will use HashiCorp Configuration Language (HCL) to define the resource configuration.

Prerequisites

  • Terraform Version: 1.5.0 or later.
  • Provider Version: mikeschinkel/genesys-cloud version 1.0.0 or later.
  • Genesys Cloud Organization: An active organization with API access.
  • API Credentials: A Genesys Cloud API user with the following permissions:
    • queue:queue:read
    • queue:queue:write
    • routing:skill:read
    • routing:wrapupcode:read
  • Environment: A terminal or IDE with Terraform installed.

Authentication Setup

The Genesys Cloud Terraform provider supports two primary authentication methods: Client Credentials Flow (recommended for CI/CD) and Personal Access Tokens (useful for local development). For this tutorial, we will use the Client Credentials Flow, which requires a client_id and client_secret.

You must configure the provider block in your Terraform file. Never hardcode secrets. Use environment variables or a secure vault.

terraform {
  required_providers {
    genesyscloud = {
      source = "mikeschinkel/genesyscloud"
      version = ">= 1.0.0"
    }
  }
}

provider "genesyscloud" {
  # Use environment variables for security.
  # Set these in your shell or CI/CD pipeline.
  # export GENESYS_CLOUD_CLIENT_ID="your-client-id"
  # export GENESYS_CLOUD_CLIENT_SECRET="your-client-secret"
  # export GENESYS_CLOUD_REGION="us-east-1"

  client_id     = var.genesys_cloud_client_id
  client_secret = var.genesys_cloud_client_secret
  region        = var.genesys_cloud_region
}

variable "genesys_cloud_client_id" {
  description = "Genesys Cloud API Client ID"
  type        = string
  sensitive   = true
}

variable "genesys_cloud_client_secret" {
  description = "Genesys Cloud API Client Secret"
  type        = string
  sensitive   = true
}

variable "genesys_cloud_region" {
  description = "Genesys Cloud Region (e.g., us-east-1, eu-west-1)"
  type        = string
  default     = "us-east-1"
}

Implementation

Step 1: Define Skills and Wrap-Up Codes

Before creating a queue, you must define the skills and wrap-up codes that the queue will use. Genesys Cloud queues rely on these routing entities to distribute work. If these entities do not exist, the queue creation will fail or the queue will not route effectively.

We will create two skills: Billing and Technical_Support. We will also create a wrap-up code: Case_Resolved.

resource "genesyscloud_routing_skill" "billing_skill" {
  name        = "Billing"
  description = "Skill for handling billing inquiries"
}

resource "genesyscloud_routing_skill" "tech_skill" {
  name        = "Technical_Support"
  description = "Skill for handling technical support issues"
}

resource "genesyscloud_routing_wrapup_code" "case_resolved" {
  name        = "Case Resolved"
  description = "Used when a customer case is fully resolved"
  enabled     = true
}

Expected Response:
When you run terraform plan, Terraform will identify these resources as new. The provider will call the Genesys Cloud API endpoints /api/v2/routing/skills and /api/v2/routing/wrapupcodes to create these entities.

Error Handling:
If a skill with the same name already exists, the provider may throw a 409 Conflict error. The mikeschinkel provider typically handles this by attempting to import the existing resource if it matches the configuration, but it is best practice to use unique names or data sources for pre-existing skills.

Step 2: Create the Queue

Now we define the queue itself. The queue resource requires several parameters:

  • name: The display name of the queue.
  • description: A description of the queue.
  • empty_queue_behavior: What happens when no agents are available. Options include QUEUE, DROP, or TRANSFER.
  • enable_apd: Whether to enable Average Post-Diagnosis (APD) for forecasting.
  • max_wait: The maximum time (in seconds) a conversation can wait in the queue.
  • outbound_email_enabled: Whether to allow outbound emails from this queue.
  • queue_email: The email address associated with the queue (required if outbound_email_enabled is true).
  • skills: A list of skill IDs that agents must have to be routed to this queue.
  • wrap_up_codes: A list of wrap-up code IDs that agents can select after a conversation.
resource "genesyscloud_queue" "support_queue" {
  name                = "Customer Support Queue"
  description         = "Primary queue for customer support interactions"
  empty_queue_behavior = "QUEUE"
  enable_apd          = true
  max_wait            = 1200 # 20 minutes
  outbound_email_enabled = false
  # queue_email       = "support@example.com" # Uncomment if outbound_email_enabled is true

  # Reference the skills created in Step 1
  skills = [
    genesyscloud_routing_skill.billing_skill.id,
    genesyscloud_routing_skill.tech_skill.id
  ]

  # Reference the wrap-up code created in Step 1
  wrap_up_codes = [
    genesyscloud_routing_wrapup_code.case_resolved.id
  ]

  # Optional: Set the queue's routing strategy
  # Default is LONGEST_IDLE_AGENT
  # routing_strategy = "LONGEST_IDLE_AGENT"
}

Expected Response:
The provider will call /api/v2/queues with a POST request. The request body will include the skills and wrap-up codes as references. A successful response returns the queue ID and details.

Error Handling:

  • 400 Bad Request: Occurs if required fields are missing or invalid (e.g., max_wait is negative).
  • 403 Forbidden: Occurs if the API user does not have queue:queue:write permissions.
  • 422 Unprocessable Entity: Occurs if referenced skills or wrap-up codes do not exist.

Step 3: Configure Queue Members (Optional)

While not strictly required to define the queue, it is common to add agents to the queue. This step demonstrates how to link agents to the queue using the genesyscloud_queue_member resource.

# Data source to find an existing user by email
data "genesyscloud_user" "agent_user" {
  email = "agent@example.com"
}

resource "genesyscloud_queue_member" "agent_assignment" {
  queue_id = genesyscloud_queue.support_queue.id
  user_id  = data.genesyscloud_user.agent_user.id
  priority = 1 # Lower number means higher priority
  skill_level = 1 # 1-5, where 5 is the highest skill level for this queue
}

Expected Response:
The provider will call /api/v2/queues/{queueId}/members to add the agent. The response confirms the agent’s assignment and priority.

Error Handling:

  • 404 Not Found: Occurs if the user ID or queue ID is invalid.
  • 409 Conflict: Occurs if the agent is already a member of the queue with the same priority.

Step 4: Handle Dependencies and State

Terraform manages state to track resources. When you create a queue that depends on skills, Terraform ensures the skills are created first. This is handled automatically by the provider’s dependency graph.

However, if you are importing existing resources, you must import them in the correct order:

  1. Import skills.
  2. Import wrap-up codes.
  3. Import the queue.
# Example import commands
terraform import genesyscloud_routing_skill.billing_skill <skill-id>
terraform import genesyscloud_routing_skill.tech_skill <tech-skill-id>
terraform import genesyscloud_routing_wrapup_code.case_resolved <wrapup-code-id>
terraform import genesyscloud_queue.support_queue <queue-id>

Complete Working Example

Here is the complete Terraform configuration file (main.tf) that combines all steps.

terraform {
  required_providers {
    genesyscloud = {
      source = "mikeschinkel/genesyscloud"
      version = ">= 1.0.0"
    }
  }
}

provider "genesyscloud" {
  client_id     = var.genesys_cloud_client_id
  client_secret = var.genesys_cloud_client_secret
  region        = var.genesys_cloud_region
}

variable "genesys_cloud_client_id" {
  description = "Genesys Cloud API Client ID"
  type        = string
  sensitive   = true
}

variable "genesys_cloud_client_secret" {
  description = "Genesys Cloud API Client Secret"
  type        = string
  sensitive   = true
}

variable "genesys_cloud_region" {
  description = "Genesys Cloud Region"
  type        = string
  default     = "us-east-1"
}

# Step 1: Define Skills
resource "genesyscloud_routing_skill" "billing_skill" {
  name        = "Billing"
  description = "Skill for handling billing inquiries"
}

resource "genesyscloud_routing_skill" "tech_skill" {
  name        = "Technical_Support"
  description = "Skill for handling technical support issues"
}

# Step 1: Define Wrap-Up Code
resource "genesyscloud_routing_wrapup_code" "case_resolved" {
  name        = "Case Resolved"
  description = "Used when a customer case is fully resolved"
  enabled     = true
}

# Step 2: Create the Queue
resource "genesyscloud_queue" "support_queue" {
  name                = "Customer Support Queue"
  description         = "Primary queue for customer support interactions"
  empty_queue_behavior = "QUEUE"
  enable_apd          = true
  max_wait            = 1200
  outbound_email_enabled = false

  skills = [
    genesyscloud_routing_skill.billing_skill.id,
    genesyscloud_routing_skill.tech_skill.id
  ]

  wrap_up_codes = [
    genesyscloud_routing_wrapup_code.case_resolved.id
  ]
}

# Step 3: Optional - Add an Agent (Uncomment and provide valid user email)
# data "genesyscloud_user" "agent_user" {
#   email = "agent@example.com"
# }

# resource "genesyscloud_queue_member" "agent_assignment" {
#   queue_id    = genesyscloud_queue.support_queue.id
#   user_id     = data.genesyscloud_user.agent_user.id
#   priority    = 1
#   skill_level = 1
# }

To apply this configuration:

# Initialize the provider
terraform init

# Plan the changes
terraform plan

# Apply the changes
terraform apply

Common Errors & Debugging

Error: 403 Forbidden

Cause: The API user does not have the required permissions.
Fix: Ensure the API user has the following roles or custom permissions:

  • queue:queue:write
  • routing:skill:write
  • routing:wrapupcode:write

You can verify permissions by checking the user’s role in the Genesys Cloud Admin Console or by calling /api/v2/users/me and inspecting the permissions field.

Error: 409 Conflict

Cause: A resource with the same name already exists, or the provider is trying to create a resource that it thinks is new but already exists in Genesys Cloud.
Fix:

  1. Check if the skill, wrap-up code, or queue already exists in Genesys Cloud.
  2. If it does, use terraform import to bring it into state.
  3. If it does not, ensure the name is unique.

Error: 422 Unprocessable Entity

Cause: Referenced resources (skills, wrap-up codes) do not exist or are invalid.
Fix:

  1. Verify that the skill IDs and wrap-up code IDs are correct.
  2. Ensure that the skills and wrap-up codes are created before the queue is created. Terraform handles this automatically if you reference resources directly (e.g., genesyscloud_routing_skill.billing_skill.id).

Error: Provider Initialization Failed

Cause: Invalid client_id, client_secret, or region.
Fix:

  1. Check your environment variables or variable definitions.
  2. Ensure the region is correct (e.g., us-east-1, eu-west-1, ap-southeast-2).
  3. Verify that the client credentials are for a valid API user in the specified region.

Official References