Export All Architect Flows as JSON Using the CX as Code CLI
What You Will Build
- This tutorial demonstrates how to extract every Architect flow definition from a Genesys Cloud CX organization into individual JSON files.
- The solution utilizes the Genesys Cloud CX as Code CLI (
genesyscloud), which wraps the underlying REST API to handle authentication and resource discovery. - The implementation uses Bash scripting for orchestration and JSON processing with
jqfor validation.
Prerequisites
- Genesys Cloud CX Account: Admin or Architect role permissions are required to read flow definitions.
- CX as Code CLI: Version 2.11.0 or later. Ensure it is installed and available in your system PATH.
- jq: A lightweight command-line JSON processor. Install via
apt install jq,brew install jq, or equivalent package manager. - Environment Variables: You must have
GENESYS_CLOUD_REGION,GENESYS_CLOUD_CLIENT_ID, andGENESYS_CLOUD_CLIENT_SECRETconfigured in your shell environment or.envfile. - Operating System: macOS, Linux, or Windows (WSL recommended for consistent Bash behavior).
Authentication Setup
The CX as Code CLI manages OAuth tokens automatically when environment variables are present. Before running any export commands, verify that the CLI can authenticate successfully.
Run the following command to test the connection and retrieve the organization details. This confirms that your credentials are valid and that the CLI has the necessary scope to access Architect resources.
genesyscloud auth:login --client-id $GENESYS_CLOUD_CLIENT_ID --client-secret $GENESYS_CLOUD_CLIENT_SECRET --region $GENESYS_CLOUD_REGION
If successful, the CLI will output a confirmation message indicating that the token has been cached. The CLI caches the access token in a local file (typically ~/.genesyscloud/genesyscloud.json). This token is automatically refreshed if it expires during long-running operations.
To verify the active session and the associated organization ID, run:
genesyscloud auth:whoami
The output will display the user ID, the organization ID, and the region. Record the organizationId if you need to reference it in subsequent API calls, although the CLI usually handles this context implicitly.
Implementation
Step 1: Discover All Architect Flows
The first step is to retrieve the list of all flow IDs and their associated metadata (name, type, description). The Genesys Cloud API paginates results, but the CX as Code CLI handles pagination automatically when using the architect:flows:list command.
We will execute the list command and pipe the output to a file. This avoids memory issues if the organization has thousands of flows.
# Create a directory for the export
mkdir -p /tmp/genesys_export/flows
# List all flows and save to a temporary JSON file
genesyscloud architect:flows:list --output-format json > /tmp/genesys_export/flows_list.json
The resulting flows_list.json file contains an array of flow objects. A single entry in this array looks like this:
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Sales Inbound Flow",
"version": 12,
"type": "voice",
"description": "Handles all incoming sales calls.",
"selfUri": "/api/v2/architect/flows/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
We need to iterate over this list to export each flow individually. We will use jq to extract the id and name for each flow.
Step 2: Export Each Flow Definition
Now that we have the list of flows, we need to fetch the full JSON definition for each one. The architect:flows:get command retrieves the complete schema of a specific flow, including all blocks, conditions, and variables.
We will create a Bash script that iterates through the list of flows and exports each one. This approach is more robust than running a single command because it allows for error handling per flow.
Create a file named export_flows.sh with the following content:
#!/bin/bash
# Configuration
EXPORT_DIR="/tmp/genesys_export/flows"
LIST_FILE="/tmp/genesys_export/flows_list.json"
LOG_FILE="/tmp/genesys_export/export.log"
# Ensure directories exist
mkdir -p "$EXPORT_DIR"
# Initialize log file
echo "Export started at $(date)" > "$LOG_FILE"
# Check if the list file exists
if [ ! -f "$LIST_FILE" ]; then
echo "Error: Flows list file not found. Run the list command first." | tee -a "$LOG_FILE"
exit 1
fi
# Count total flows
TOTAL_FLOWS=$(jq 'length' "$LIST_FILE")
echo "Total flows to export: $TOTAL_FLOWS" | tee -a "$LOG_FILE"
# Iterate over each flow
for i in $(seq 0 $((TOTAL_FLOWS - 1))); do
# Extract flow ID and name
FLOW_ID=$(jq -r ".[$i].id" "$LIST_FILE")
FLOW_NAME=$(jq -r ".[$i].name" "$LIST_FILE")
FLOW_TYPE=$(jq -r ".[$i].type" "$LIST_FILE")
# Sanitize the filename: replace spaces and special characters with underscores
SAFE_NAME=$(echo "$FLOW_NAME" | sed 's/[^a-zA-Z0-9_-]/_/g')
# Define output filename
OUTPUT_FILE="${EXPORT_DIR}/${SAFE_NAME}_${FLOW_ID}.json"
echo "Exporting flow: $FLOW_NAME ($FLOW_ID)..." | tee -a "$LOG_FILE"
# Execute the export command
# The --output-format json flag ensures raw JSON output
genesyscloud architect:flows:get --id "$FLOW_ID" --output-format json > "$OUTPUT_FILE"
# Check if the command succeeded
if [ $? -eq 0 ]; then
# Validate the JSON output
if jq empty "$OUTPUT_FILE" 2>/dev/null; then
echo "Success: $FLOW_NAME exported to $OUTPUT_FILE" | tee -a "$LOG_FILE"
else
echo "Error: Invalid JSON for flow $FLOW_NAME" | tee -a "$LOG_FILE"
fi
else
echo "Error: Failed to export flow $FLOW_NAME ($FLOW_ID)" | tee -a "$LOG_FILE"
# Optional: Retry logic could be added here
# For now, we continue to the next flow
fi
# Small delay to avoid rate limiting if processing a large number of flows
sleep 0.5
done
echo "Export completed at $(date)" | tee -a "$LOG_FILE"
Make the script executable and run it:
chmod +x export_flows.sh
./export_flows.sh
Step 3: Handle Edge Cases and Rate Limiting
When exporting a large number of flows, you may encounter HTTP 429 (Too Many Requests) errors. The CX as Code CLI has built-in retry logic, but it is not always aggressive enough for bulk operations. The sleep 0.5 in the script above helps mitigate this, but you may need to adjust it based on your organization’s size.
If you encounter persistent rate limiting, you can increase the delay or implement a more sophisticated backoff strategy. For example, you can modify the error handling section to retry with exponential backoff:
# Enhanced error handling with retry
RETRY_COUNT=0
MAX_RETRIES=3
SUCCESS=false
while [ $RETRY_COUNT -lt $MAX_RETRIES ] && [ "$SUCCESS" = false ]; do
genesyscloud architect:flows:get --id "$FLOW_ID" --output-format json > "$OUTPUT_FILE"
if [ $? -eq 0 ] && jq empty "$OUTPUT_FILE" 2>/dev/null; then
SUCCESS=true
echo "Success: $FLOW_NAME exported" | tee -a "$LOG_FILE"
else
RETRY_COUNT=$((RETRY_COUNT + 1))
BACKOFF=$((2 ** RETRY_COUNT))
echo "Retry $RETRY_COUNT/$MAX_RETRIES for flow $FLOW_NAME in $BACKOFF seconds..." | tee -a "$LOG_FILE"
sleep $BACKOFF
fi
done
if [ "$SUCCESS" = false ]; then
echo "Failed to export flow $FLOW_NAME after $MAX_RETRIES retries" | tee -a "$LOG_FILE"
fi
Complete Working Example
Below is the complete, consolidated script that performs the entire process: authentication check, flow listing, and individual flow export. This script is designed to be copy-pasted and run with minimal modification.
#!/bin/bash
# ==============================================================================
# Genesys Cloud CX Architect Flow Exporter
# ==============================================================================
# This script exports all Architect flows from a Genesys Cloud organization
# to individual JSON files using the CX as Code CLI.
# ==============================================================================
set -e # Exit on any error
# Configuration
EXPORT_DIR="./genesys_flows_export"
LIST_FILE="${EXPORT_DIR}/flows_list.json"
LOG_FILE="${EXPORT_DIR}/export.log"
REGION="${GENESYS_CLOUD_REGION:-us-east-1}" # Default region if not set
# Colors for terminal output
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Function to log messages
log() {
local level=$1
local message=$2
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
echo -e "${timestamp} [${level}] ${message}" | tee -a "$LOG_FILE"
}
# Function to check prerequisites
check_prerequisites() {
if ! command -v genesyscloud &> /dev/null; then
log "ERROR" "genesyscloud CLI not found. Please install it."
exit 1
fi
if ! command -v jq &> /dev/null; then
log "ERROR" "jq not found. Please install it."
exit 1
fi
if [ -z "$GENESYS_CLOUD_CLIENT_ID" ] || [ -z "$GENESYS_CLOUD_CLIENT_SECRET" ]; then
log "ERROR" "GENESYS_CLOUD_CLIENT_ID and GENESYS_CLOUD_CLIENT_SECRET must be set."
exit 1
fi
mkdir -p "$EXPORT_DIR"
log "INFO" "Prerequisites check passed."
}
# Function to authenticate
authenticate() {
log "INFO" "Authenticating with Genesys Cloud..."
if genesyscloud auth:login --client-id "$GENESYS_CLOUD_CLIENT_ID" --client-secret "$GENESYS_CLOUD_CLIENT_SECRET" --region "$REGION" --output-format text > /dev/null 2>&1; then
log "INFO" "Authentication successful."
else
log "ERROR" "Authentication failed. Check your credentials."
exit 1
fi
}
# Function to list flows
list_flows() {
log "INFO" "Retrieving list of all flows..."
genesyscloud architect:flows:list --output-format json > "$LIST_FILE"
if [ ! -s "$LIST_FILE" ]; then
log "ERROR" "Failed to retrieve flows list."
exit 1
fi
local count=$(jq 'length' "$LIST_FILE")
log "INFO" "Found $count flows."
}
# Function to export flows
export_flows() {
local total=$(jq 'length' "$LIST_FILE")
local success_count=0
local fail_count=0
log "INFO" "Starting export of $total flows..."
for i in $(seq 0 $((total - 1))); do
local flow_id=$(jq -r ".[$i].id" "$LIST_FILE")
local flow_name=$(jq -r ".[$i].name" "$LIST_FILE")
local flow_type=$(jq -r ".[$i].type" "$LIST_FILE")
# Sanitize filename
local safe_name=$(echo "$flow_name" | sed 's/[^a-zA-Z0-9_-]/_/g')
local output_file="${EXPORT_DIR}/${safe_name}_${flow_id}.json"
log "INFO" "[$((i + 1))/$total] Exporting: $flow_name"
# Retry logic
local retries=0
local max_retries=3
local exported=false
while [ $retries -lt $max_retries ] && [ "$exported" = false ]; do
if genesyscloud architect:flows:get --id "$flow_id" --output-format json > "$output_file" 2>/dev/null; then
if jq empty "$output_file" 2>/dev/null; then
exported=true
success_count=$((success_count + 1))
log "INFO" "Successfully exported: $flow_name"
else
log "WARN" "Invalid JSON for $flow_name. Retrying..."
retries=$((retries + 1))
fi
else
log "WARN" "API error for $flow_name. Retrying..."
retries=$((retries + 1))
fi
if [ "$exported" = false ] && [ $retries -lt $max_retries ]; then
sleep 2
fi
done
if [ "$exported" = false ]; then
fail_count=$((fail_count + 1))
log "ERROR" "Failed to export: $flow_name after $max_retries retries"
rm -f "$output_file"
fi
done
log "INFO" "Export complete. Success: $success_count, Failed: $fail_count"
}
# Main execution
main() {
check_prerequisites
authenticate
list_flows
export_flows
log "INFO" "All operations completed. Files are in: $EXPORT_DIR"
}
main
Common Errors & Debugging
Error: 401 Unauthorized
- Cause: The OAuth token has expired or the client credentials are incorrect.
- Fix: Re-run the
genesyscloud auth:logincommand. Ensure that theGENESYS_CLOUD_CLIENT_IDandGENESYS_CLOUD_CLIENT_SECRETenvironment variables are set correctly. Check that the client has theadminorarchitect:flow:viewscope.
Error: 429 Too Many Requests
- Cause: You are sending requests faster than the Genesys Cloud API allows.
- Fix: Increase the
sleepduration in the script. The defaultsleep 0.5orsleep 2in the retry logic should help. If you are exporting thousands of flows, consider increasing the delay to 5 seconds.
Error: 403 Forbidden
- Cause: The user associated with the OAuth client does not have permission to view Architect flows.
- Fix: Verify that the user has the
architect:flow:viewcapability in their Genesys Cloud role. Assign the user to a role that includes this capability, such as “Architect” or “Administrator”.
Error: Invalid JSON
- Cause: The API returned an error message instead of the flow definition, or the file was truncated.
- Fix: Check the
export.logfile for API error messages. Ensure that thegenesyscloudCLI is up to date. If the issue persists, try exporting a single flow manually usinggenesyscloud architect:flows:get --id <FLOW_ID>to isolate the problem.