Fetch All Queues Across Multiple Divisions Using the Genesys Cloud Platform SDK for JavaScript
What You Will Build
- A Node.js script that authenticates with the Genesys Cloud Platform and retrieves a complete list of all queues, regardless of division.
- This tutorial uses the official
@gencloud/gencloud-nodeSDK (version 10+). - The implementation is written in JavaScript (ES Modules) using modern
async/awaitsyntax.
Prerequisites
- OAuth Client Type: Service Account (Client Credentials Flow).
- Required Scopes:
queue:view(to read queue details) anduser:readis not required for this specific task, butdivision:readmay be helpful for debugging division IDs. The minimum isqueue:view. - SDK Version:
@gencloud/gencloud-nodev10.0.0 or higher. - Runtime: Node.js v18 or higher.
- External Dependencies:
dotenvfor environment variable management.
Authentication Setup
The Genesys Cloud Platform SDK handles the OAuth 2.0 Client Credentials flow automatically when you initialize the PlatformClient with your credentials. However, you must provide the Client ID, Client Secret, and Environment.
First, install the required dependencies:
npm install @gencloud/gencloud-node dotenv
Create a .env file in your project root:
GENESYS_CLIENT_ID=your_client_id_here
GENESYS_CLIENT_SECRET=your_client_secret_here
GENESYS_ENVIRONMENT=us-east-1
In your JavaScript module, initialize the SDK. The PlatformClient is a singleton pattern; you only need to configure it once.
import dotenv from 'dotenv';
import { PlatformClient } from '@gencloud/gencloud-node';
dotenv.config();
// Initialize the Platform Client
const platformClient = PlatformClient.createInstance();
// Configure authentication
platformClient.setEnvironment(process.env.GENESYS_ENVIRONMENT);
platformClient.loginClientCredentials(
process.env.GENESYS_CLIENT_ID,
process.env.GENESYS_CLIENT_SECRET
);
// Verify authentication is ready
async function verifyAuth() {
try {
const user = await platformClient.Users.getUserMe();
console.log(`Authenticated as: ${user.name} (${user.id})`);
} catch (error) {
console.error('Authentication failed:', error.message);
throw error;
}
}
Implementation
Step 1: Retrieve All Divisions
The critical insight here is that Genesys Cloud resources are scoped to divisions. A simple call to getQueues without a division ID only returns queues in the default division. To fetch all queues, you must first identify every division in the organization.
We use the DivisionsApi to list all divisions. This endpoint supports pagination, but for most organizations, the default page size returns all divisions in one request. We will handle pagination to be robust.
async function getAllDivisions() {
const divisionsApi = platformClient.DivisionsApi;
let allDivisions = [];
let nextPageSequenceId = null;
let hasMore = true;
console.log('Fetching divisions...');
while (hasMore) {
try {
// Fetch with a large page size to minimize requests
const response = await divisionsApi.getDivisions({
pageSize: 100,
pageSequenceId: nextPageSequenceId
});
if (response.entities && response.entities.length > 0) {
allDivisions = [...allDivisions, ...response.entities];
}
// Check if there are more pages
if (response.nextPageSequenceId) {
nextPageSequenceId = response.nextPageSequenceId;
} else {
hasMore = false;
}
} catch (error) {
console.error('Error fetching divisions:', error);
throw error;
}
}
console.log(`Found ${allDivisions.length} divisions.`);
return allDivisions;
}
Step 2: Fetch Queues for Each Division
Now that we have the list of divisions, we iterate through them and call the QueuesApi for each division ID.
Important: The getQueues endpoint allows you to specify a divisionId. If you omit it, it defaults to the user’s primary division. We must explicitly pass the divisionId for every division returned in Step 1.
We must also handle pagination for queues, as large organizations may have hundreds or thousands of queues across divisions.
async function getQueuesForDivision(divisionId) {
const queuesApi = platformClient.QueuesApi;
let allQueues = [];
let nextPageSequenceId = null;
let hasMore = true;
while (hasMore) {
try {
const response = await queuesApi.getQueues({
divisionId: divisionId,
pageSize: 100, // Max recommended page size
pageSequenceId: nextPageSequenceId
});
if (response.entities && response.entities.length > 0) {
allQueues = [...allQueues, ...response.entities];
}
if (response.nextPageSequenceId) {
nextPageSequenceId = response.nextPageSequenceId;
} else {
hasMore = false;
}
} catch (error) {
// Handle 403 Forbidden: The service account may not have access to specific divisions
if (error.status === 403) {
console.warn(`Access denied to division: ${divisionId}`);
return [];
}
console.error(`Error fetching queues for division ${divisionId}:`, error.message);
throw error;
}
}
return allQueues;
}
Step 3: Aggregate and Process Results
Fetching queues sequentially can be slow if you have many divisions. However, making hundreds of parallel requests can trigger rate limits (429 Too Many Requests). A balanced approach is to use a concurrency limiter or process divisions in batches.
For simplicity and robustness in this tutorial, we will process divisions sequentially but log progress. In a production environment with 50+ divisions, consider using Promise.all with a chunking strategy or a library like p-limit.
async function fetchAllQueues() {
const divisions = await getAllDivisions();
const allQueuesMap = new Map(); // Key: Division ID, Value: Array of Queues
for (const division of divisions) {
console.log(`Fetching queues for division: ${division.name} (${division.id})`);
const queues = await getQueuesForDivision(division.id);
allQueuesMap.set(division.id, queues);
// Optional: Small delay to respect rate limits if divisions are many
await new Promise(resolve => setTimeout(resolve, 100));
}
// Flatten the map into a single array for easier processing
const allQueues = Array.from(allQueuesMap.values()).flat();
console.log(`Total queues fetched: ${allQueues.length}`);
return allQueues;
}
Complete Working Example
Below is the full, copy-pasteable Node.js module. Save this as fetch-all-queues.mjs.
import dotenv from 'dotenv';
import { PlatformClient } from '@gencloud/gencloud-node';
// Load environment variables
dotenv.config();
// Validate environment variables
if (!process.env.GENESYS_CLIENT_ID || !process.env.GENESYS_CLIENT_SECRET || !process.env.GENESYS_ENVIRONMENT) {
console.error('Missing required environment variables: GENESYS_CLIENT_ID, GENESYS_CLIENT_SECRET, GENESYS_ENVIRONMENT');
process.exit(1);
}
// Initialize Platform Client
const platformClient = PlatformClient.createInstance();
platformClient.setEnvironment(process.env.GENESYS_ENVIRONMENT);
// Login
platformClient.loginClientCredentials(
process.env.GENESYS_CLIENT_ID,
process.env.GENESYS_CLIENT_SECRET
);
/**
* Fetches all divisions in the organization with pagination support.
* @returns {Promise<Array>} Array of division objects
*/
async function getAllDivisions() {
const divisionsApi = platformClient.DivisionsApi;
let allDivisions = [];
let nextPageSequenceId = null;
let hasMore = true;
console.log('Step 1: Fetching all divisions...');
while (hasMore) {
try {
const response = await divisionsApi.getDivisions({
pageSize: 100,
pageSequenceId: nextPageSequenceId
});
if (response.entities && response.entities.length > 0) {
allDivisions = [...allDivisions, ...response.entities];
}
if (response.nextPageSequenceId) {
nextPageSequenceId = response.nextPageSequenceId;
} else {
hasMore = false;
}
} catch (error) {
console.error('Failed to fetch divisions:', error.message);
throw error;
}
}
console.log(`Found ${allDivisions.length} divisions.`);
return allDivisions;
}
/**
* Fetches all queues for a specific division with pagination support.
* @param {string} divisionId - The ID of the division
* @returns {Promise<Array>} Array of queue objects
*/
async function getQueuesForDivision(divisionId) {
const queuesApi = platformClient.QueuesApi;
let allQueues = [];
let nextPageSequenceId = null;
let hasMore = true;
while (hasMore) {
try {
const response = await queuesApi.getQueues({
divisionId: divisionId,
pageSize: 100,
pageSequenceId: nextPageSequenceId
});
if (response.entities && response.entities.length > 0) {
allQueues = [...allQueues, ...response.entities];
}
if (response.nextPageSequenceId) {
nextPageSequenceId = response.nextPageSequenceId;
} else {
hasMore = false;
}
} catch (error) {
// Handle 403 Forbidden gracefully
if (error.status === 403) {
console.warn(`[Warning] Access denied to division: ${divisionId}. Skipping.`);
return [];
}
// Handle 429 Too Many Requests with retry logic
if (error.status === 429) {
console.warn(`[Rate Limit] Waiting 1 second before retrying division: ${divisionId}`);
await new Promise(resolve => setTimeout(resolve, 1000));
continue; // Retry the same page
}
console.error(`[Error] Failed to fetch queues for division ${divisionId}:`, error.message);
throw error;
}
}
return allQueues;
}
/**
* Main function to orchestrate the fetching of all queues across all divisions.
*/
async function main() {
try {
// Step 1: Get all divisions
const divisions = await getAllDivisions();
if (divisions.length === 0) {
console.log('No divisions found.');
return;
}
// Step 2: Fetch queues for each division
let totalQueuesCount = 0;
const allQueues = [];
console.log(`\nStep 2: Fetching queues from ${divisions.length} divisions...`);
for (const division of divisions) {
const queues = await getQueuesForDivision(division.id);
allQueues.push(...queues);
totalQueuesCount += queues.length;
// Log progress every 10 divisions
if (divisions.indexOf(division) % 10 === 0) {
console.log(`Processed ${divisions.indexOf(division) + 1} divisions. Total queues so far: ${totalQueuesCount}`);
}
}
// Step 3: Output results
console.log(`\n--- Complete ---`);
console.log(`Total Queues Fetched: ${allQueues.length}`);
// Example: Print first 5 queues
if (allQueues.length > 0) {
console.log('\nSample Queues:');
allQueues.slice(0, 5).forEach(queue => {
console.log(`- ${queue.name} (ID: ${queue.id}, Division: ${queue.division.name})`);
});
}
} catch (error) {
console.error('Fatal error in main execution:', error);
process.exit(1);
}
}
// Run the script
main();
Common Errors & Debugging
Error: 401 Unauthorized
- Cause: The Client ID or Client Secret is incorrect, or the environment is wrong (e.g., using
us-east-1credentials for aeu-west-1org). - Fix: Verify your
.envvalues. Ensure the Service Account exists in the Genesys Cloud Admin portal under Admin > Users > Service Accounts.
Error: 403 Forbidden
- Cause: The Service Account does not have the
queue:viewscope, or it is not assigned to the roles/divisions that contain the queues. - Fix:
- Go to Admin > Security > OAuth Clients.
- Edit your Service Account.
- Ensure
queue:viewis checked in the Scopes section. - Ensure the Service Account is assigned to a role that has visibility into the divisions containing the queues.
Error: 429 Too Many Requests
- Cause: You are making too many API calls in a short period. The Genesys Cloud API has rate limits per client ID.
- Fix: Implement exponential backoff. The code example above includes a simple 1-second delay on 429 errors. For production systems, use a dedicated retry library like
axios-retryor implement a token bucket algorithm.
Error: “divisionId” is required
- Cause: Attempting to call
getQueueswithout specifying adivisionIdwhen the user context has multiple divisions, or the SDK default behavior is unexpected. - Fix: Always explicitly pass the
divisionIdparameter when callinggetQueues. Never rely on the default division unless you specifically want only that division.