CXone Studio Snippet: Execute REST API Calls and Parse JSON Responses
What You Will Build
- A CXone Studio Snippet that executes an outbound HTTP GET request to a public REST API and parses the returned JSON payload into a usable object.
- The logic utilizes the native
httpservice available within the CXone Studio JavaScript runtime environment. - The implementation is written in JavaScript, which is the standard language for CXone Studio Snippets.
Prerequisites
- Platform: NICE CXone Studio (formerly Five9 Studio).
- Access: You must have access to a CXone Studio environment with the ability to create and debug Snippets.
- Concept: Familiarity with asynchronous JavaScript (
async/await) and JSON structure. - No External Libraries: CXone Studio Snippets run in a sandboxed environment. You cannot use
npmpackages likeaxiosorfetch. You must use the built-inhttpservice provided by the Studio runtime.
Authentication Setup
CXone Studio Snippets do not require a separate OAuth authentication block for internal execution because they run in the context of the authenticated user or the system service account depending on the flow configuration. However, if the REST API you are calling requires authentication (e.g., an external CRM or internal microservice), you must handle the header injection within the Snippet code.
For this tutorial, we will use a public endpoint (https://jsonplaceholder.typicode.com/posts/1) that does not require authentication. If you were calling a protected resource, you would include an Authorization header in the options object passed to the http service.
Implementation
Step 1: Initialize the Snippet and Define Variables
A CXone Studio Snippet is essentially a function that accepts an input object (often containing session variables) and returns an output object. The first step is to define the entry point and declare the variables needed to hold the API response.
In CXone Studio, the http service is accessed via the global services object. Specifically, services.http provides methods like get, post, put, and delete.
/**
* CXone Studio Snippet: REST API Call
*
* @param {object} input - The input object passed from the Studio flow.
* @returns {object} - The output object to be used in subsequent flow steps.
*/
function main(input) {
// Initialize output object with default values
let output = {
success: false,
statusCode: null,
errorMessage: null,
apiData: null
};
try {
// Step 1 logic will be implemented here
} catch (error) {
output.errorMessage = error.message;
log.error("Snippet Error: " + error.message);
}
return output;
}
Key Points:
- The
mainfunction is the standard entry point for CXone Studio Snippets. - The
outputobject structure should match the “Outputs” defined in the Snippet configuration within the Studio UI. - The
try/catchblock ensures that any runtime errors do not crash the entire call flow but are instead captured in theerrorMessagefield.
Step 2: Construct the HTTP Request
The core of the task is invoking the http service. We will use the get method. The method signature typically looks like services.http.get(url, options).
The options object allows you to define headers, timeout, and other HTTP parameters. It is critical to set the Accept header to application/json to ensure the server returns JSON.
// Define the target URL
const apiUrl = "https://jsonplaceholder.typicode.com/posts/1";
// Define request options
const requestOptions = {
headers: {
"Accept": "application/json",
"Content-Type": "application/json"
// If authentication were required:
// "Authorization": "Bearer " + input.authToken
},
timeout: 5000 // 5 seconds timeout
};
// Execute the HTTP GET request
// Note: services.http.get returns a Promise
const response = await services.http.get(apiUrl, requestOptions);
Important Considerations:
- Async/Await: The
services.httpmethods are asynchronous. You must useawaitto pause execution until the response is received. If you do not useawait, the snippet will proceed before the data arrives, resulting inundefineddata. - Timeout: Always set a timeout. If the external API hangs, the voice call will wait indefinitely, leading to poor customer experience and potential queue buildup.
- Headers: Explicitly setting
Content-TypeandAcceptprevents negotiation issues with the target server.
Step 3: Handle the Response and Parse JSON
The response object returned by services.http.get contains metadata (status code, headers) and the body. In CXone Studio, the body is often returned as a string if the content type is JSON, or it may be automatically parsed depending on the specific Studio version and configuration. To be safe and explicit, we should parse it manually if it is a string, or access the parsed property if it exists.
We also need to check the HTTP status code. A 200 OK does not always mean the application logic succeeded, but for this tutorial, we will treat any 2xx status as a success.
// Check HTTP Status Code
if (response && response.statusCode >= 200 && response.statusCode < 300) {
// The body might be a string or an object.
// We check if it is a string to handle parsing safely.
let parsedBody;
if (typeof response.body === 'string') {
try {
parsedBody = JSON.parse(response.body);
} catch (parseError) {
throw new Error("Invalid JSON response from API: " + parseError.message);
}
} else {
// Already parsed by the SDK
parsedBody = response.body;
}
// Extract specific data from the JSON
// For jsonplaceholder, the structure is: { userId, id, title, body }
output.apiData = {
id: parsedBody.id,
title: parsedBody.title,
body: parsedBody.body
};
output.statusCode = response.statusCode;
output.success = true;
log.info("Successfully retrieved API data. ID: " + output.apiData.id);
} else {
// Handle non-2xx status codes
let errorMsg = "API Request Failed. Status Code: " + (response ? response.statusCode : "Unknown");
if (response && response.body) {
errorMsg += ". Response: " + (typeof response.body === 'string' ? response.body : JSON.stringify(response.body));
}
throw new Error(errorMsg);
}
Edge Cases:
- Empty Body: If the API returns a
204 No Content, the body will be null or empty. Your code should handle this gracefully. - Malformed JSON: If the server returns HTML (e.g., a 404 error page) instead of JSON,
JSON.parsewill throw an error. The innertry/catchhandles this. - Data Mapping: We map the raw JSON fields to our
output.apiDataobject. This keeps the output clean and predictable for the rest of the Studio flow.
Step 4: Integrate with Studio Flow Variables
CXone Studio allows you to pass variables into the snippet and receive them back. The input object contains these values. If you need to pass a dynamic URL or authentication token from the flow, you access it via input.variableName.
// Example of using dynamic input
// const dynamicUrl = input.apiUrl || "https://jsonplaceholder.typicode.com/posts/1";
// const authToken = input.authToken;
This ensures the snippet is reusable across different flows with different endpoints.
Complete Working Example
Below is the full, copy-pasteable code for the CXone Studio Snippet. Ensure that in the Studio UI, you define the Snippet Inputs (if any) and Outputs (success, statusCode, errorMessage, apiData) to match the JavaScript object structure.
/**
* CXone Studio Snippet: REST API Call and JSON Parser
*
* Description: Makes an HTTP GET request to a specified URL and parses the JSON response.
*
* Inputs (Optional):
* - apiUrl: string (Default: https://jsonplaceholder.typicode.com/posts/1)
* - authToken: string (Optional Bearer token)
*
* Outputs:
* - success: boolean
* - statusCode: number
* - errorMessage: string
* - apiData: object (The parsed JSON data)
*/
function main(input) {
// Default output structure
let output = {
success: false,
statusCode: null,
errorMessage: null,
apiData: null
};
try {
// 1. Configure Request Parameters
// Use input.apiUrl if provided, otherwise use the default test endpoint
const targetUrl = input.apiUrl || "https://jsonplaceholder.typicode.com/posts/1";
// Construct headers
const headers = {
"Accept": "application/json",
"Content-Type": "application/json"
};
// Add Authorization header if a token is provided in input
if (input.authToken && input.authToken.length > 0) {
headers["Authorization"] = "Bearer " + input.authToken;
}
// Define request options
const options = {
headers: headers,
timeout: 5000 // 5000 ms timeout
};
// 2. Execute HTTP Request
// The 'http' service is globally available in CXone Studio
log.info("Initiating HTTP GET to: " + targetUrl);
const response = await services.http.get(targetUrl, options);
// 3. Validate HTTP Status
if (!response) {
throw new Error("No response received from the API.");
}
if (response.statusCode >= 200 && response.statusCode < 300) {
// 4. Parse JSON Body
let parsedData;
if (typeof response.body === 'string') {
if (response.body.trim() === "") {
parsedData = {};
} else {
try {
parsedData = JSON.parse(response.body);
} catch (e) {
throw new Error("Failed to parse JSON response: " + e.message);
}
}
} else {
// Assume it is already an object
parsedData = response.body;
}
// 5. Map Data to Output
// We pass the entire parsed object, but you can map specific fields here
output.apiData = parsedData;
output.statusCode = response.statusCode;
output.success = true;
log.info("API Call Successful. Status: " + response.statusCode);
} else {
// Handle HTTP Errors (4xx, 5xx)
let errorDetails = response.body;
if (typeof errorDetails === 'object') {
errorDetails = JSON.stringify(errorDetails);
}
throw new Error("HTTP Error " + response.statusCode + ": " + (errorDetails || "No body"));
}
} catch (error) {
// 6. Global Error Handling
output.success = false;
output.errorMessage = error.message;
log.error("Snippet Execution Failed: " + error.message);
// If there was a response object in the error context, try to get the status code
// Note: In this structure, the error is caught from the throw, so we might lose the status code
// unless we attach it to the error object. For simplicity, we leave statusCode as null on error.
}
return output;
}
Common Errors & Debugging
Error: services is not defined
- Cause: You are testing this code in a standard Node.js environment or browser console instead of the CXone Studio Snippet editor.
- Fix: Ensure the code is saved within a CXone Studio Snippet asset. The
servicesobject is injected by the CXone runtime.
Error: JSON.parse: unexpected end of input
- Cause: The API returned an empty body or malformed JSON (e.g., whitespace only).
- Fix: Check the
response.bodybefore parsing. Add a check forresponse.body.trim() === ""as shown in the complete example.
Error: Timeout of 5000ms exceeded
- Cause: The external API took longer than 5 seconds to respond.
- Fix: Increase the
timeoutvalue in theoptionsobject if the API is known to be slow. However, consider if the API is actually healthy. For voice flows, keep timeouts short (<10s) to avoid caller drop.
Error: 401 Unauthorized
- Cause: The API requires authentication, and the
Authorizationheader was missing or invalid. - Fix: Ensure
input.authTokenis being passed from the Studio flow into the Snippet. Verify the token format (e.g., “Bearer ” vs “Basic ”).
Error: TypeError: Cannot read property 'get' of undefined
- Cause: The
services.httpobject is not available. - Fix: This usually indicates an older version of the Studio runtime or a misconfiguration. Ensure you are using the latest Studio SDK version. In some very old environments, the service might be named differently, but
services.httpis standard for modern CXone Studio.