Export All Architect Flows as JSON Using the CX as Code CLI

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 jq for 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, and GENESYS_CLOUD_CLIENT_SECRET configured in your shell environment or .env file.
  • 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:login command. Ensure that the GENESYS_CLOUD_CLIENT_ID and GENESYS_CLOUD_CLIENT_SECRET environment variables are set correctly. Check that the client has the admin or architect:flow:view scope.

Error: 429 Too Many Requests

  • Cause: You are sending requests faster than the Genesys Cloud API allows.
  • Fix: Increase the sleep duration in the script. The default sleep 0.5 or sleep 2 in 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:view capability 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.log file for API error messages. Ensure that the genesyscloud CLI is up to date. If the issue persists, try exporting a single flow manually using genesyscloud architect:flows:get --id <FLOW_ID> to isolate the problem.

Official References