CXone Studio Snippet Action: Executing REST API Calls and Parsing JSON Responses
What You Will Build
- A CXone Studio Snippet that executes a synchronous HTTP GET request to an external or internal REST API.
- Logic to parse the returned JSON payload, extract specific fields, and store them in CXone Session Variables for downstream use.
- Implementation using the NICE CXone Studio JavaScript Snippet action, leveraging the built-in
fetchAPI.
Prerequisites
- Access: CXone Studio Designer access with permissions to create and deploy Flows.
- API Endpoint: A valid, publicly accessible REST API endpoint (or a CXone internal endpoint if using the
internalproxy configuration) that returns JSON. - CXone Session Variables: Predefined session variables in your Flow to store the incoming response data (e.g.,
api_response_status,api_data_customer_id). - JavaScript Knowledge: Familiarity with ES6+ syntax,
async/await, and JSON parsing.
Authentication Setup
CXone Studio Snippets run in a serverless, sandboxed environment. You do not manage OAuth tokens directly in the Snippet code unless you are calling an external API that requires authentication.
If you are calling a CXone internal API (e.g., /api/v2/customers/{id}), the Snippet action runs under the context of the current interaction. You must ensure the Flow has the necessary Flow Permissions enabled in the Flow Properties. The SDK automatically injects the required bearer token into the request headers when using the CXone internal proxy.
If you are calling an external API that requires API keys or OAuth:
- Store your API keys in CXone Secure Variables (Encrypted Variables).
- Reference these variables in your Snippet using the
context.variablesobject. - Construct the
Authorizationheader manually in thefetchoptions.
Example: Accessing a Secure Variable
const apiKey = context.variables.get('secure_api_key');
Implementation
Step 1: Configure the Snippet Action and Input Variables
Before writing code, you must define the inputs your Snippet will consume. In the CXone Studio Designer:
- Drag a Snippet action onto the Flow canvas.
- Open the Snippet editor.
- In the Input Variables section, add the necessary inputs. For this tutorial, we assume we are fetching customer data based on an ID provided earlier in the Flow.
Input Variable Definition:
- Name:
customerId - Type:
String - Source: Mapped from a prior session variable (e.g.,
session.customer_id).
Output Variable Definition:
- Name:
parsedResponse - Type:
JSON(orStringif you plan to parse specific fields later in the Flow logic). - Note: CXone Snippets allow returning a complex object. We will return a structured object that the Flow can then split into individual session variables.
Step 2: Construct the HTTP Request
The core of the Snippet is the JavaScript code. We will use the standard fetch API available in the CXone runtime.
Critical Consideration: The CXone Snippet runtime is asynchronous. You must return a Promise or use an async function. The platform waits for the Promise to resolve before proceeding to the next action.
Code Block: Basic Fetch Implementation
async function main() {
// 1. Retrieve input from the Flow
const customerId = context.variables.get('customerId');
if (!customerId) {
throw new Error('Customer ID is required');
}
// 2. Define the endpoint
// Using a public test API for demonstration.
// In production, replace with your internal or external endpoint.
const url = `https://jsonplaceholder.typicode.com/users/${customerId}`;
try {
// 3. Execute the HTTP GET request
const response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
// If calling an internal CXone API, you typically do NOT add
// an Authorization header here. The platform handles it via
// the internal proxy if configured correctly.
// For external APIs, add headers here:
// 'Authorization': `Bearer ${context.variables.get('external_api_token')}`
},
// Timeout is critical in serverless environments to prevent hanging
// Note: Standard fetch does not support timeout in all runtimes.
// If your runtime supports AbortController, use it. Otherwise,
// rely on the platform's default timeout (usually 10-30 seconds).
});
// 4. Check for HTTP errors (4xx, 5xx)
if (!response.ok) {
const errorText = await response.text();
throw new Error(`HTTP Error: ${response.status} - ${errorText}`);
}
// 5. Parse JSON
const data = await response.json();
// 6. Return the structured data
// The Flow will receive this object as the output variable
return {
success: true,
data: data,
statusCode: response.status
};
} catch (error) {
// Handle network errors or parsing failures
return {
success: false,
error: error.message,
data: null,
statusCode: 500
};
}
}
Step 3: Parse and Map Specific Fields
Returning the entire JSON object is useful, but often you need to extract specific fields to drive downstream logic (e.g., routing based on customer tier). CXone Snippets can return objects, but mapping complex nested JSON directly to Flow Session Variables can be tricky if you do not pre-define the structure.
It is often cleaner to extract the specific values you need inside the Snippet and return a flat object, or return the full JSON and use JSON Path expressions in the Flow to extract values later.
Approach A: Extract in Snippet (Recommended for complex logic)
async function main() {
const customerId = context.variables.get('customerId');
const url = `https://jsonplaceholder.typicode.com/users/${customerId}`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP Error: ${response.status}`);
}
const data = await response.json();
// Extract specific fields
const extractedData = {
name: data.name || 'Unknown',
email: data.email || '',
company: data.company ? data.company.name : 'No Company',
phone: data.phone || ''
};
return {
success: true,
extracted: extractedData
};
} catch (error) {
return {
success: false,
error: error.message,
extracted: null
};
}
}
Mapping Output to Flow Variables:
After the Snippet executes, you must map the returned JSON to Session Variables in the Snippet Action’s configuration.
- In the Snippet Action properties, go to Output Variables.
- Map
output.extracted.nameto Session Variablesession.customer_name. - Map
output.extracted.emailto Session Variablesession.customer_email. - Map
output.successto Session Variablesession.api_call_success(Boolean).
Step 4: Handling Internal CXone APIs (Advanced)
If you are calling a CXone API (e.g., to update a Customer record) from within a Snippet, you cannot simply use fetch('https://your-cxone-instance.nice.incontact.com/...') directly because of CORS and authentication complexity.
Instead, you should use the CXone Internal Proxy. In CXone Studio, when configuring a Snippet, there is often an option to enable “Internal API Calls” or you must use the specific cxone module if available in your specific runtime version. However, the most robust method in modern CXone Studio is to use the HTTP Request action for standard internal calls. If you must use a Snippet for complex internal logic:
- Ensure the Flow has the required API Permissions.
- Use the internal hostname (often
api.nice.incontact.comor your specific region endpoint) but note that direct fetch may fail without proper token injection. - Best Practice: For internal CXone APIs, use the dedicated CXone API Action in the Flow designer rather than a Snippet. Use Snippets primarily for external REST calls or complex data transformation.
If you are forced to use a Snippet for an internal call that requires a custom header not supported by the standard API action, you may need to retrieve the current interaction’s token. This is rarely exposed directly in Snippet JS. Therefore, the following example assumes an External API call, which is the primary use case for Snippets.
Complete Working Example
This is a complete, copy-pasteable Snippet script. It calls an external API, handles errors, parses the JSON, and returns a structured result.
Prerequisites in Flow:
- Input Variable:
customerId(String) - Output Variables:
api_success(Boolean)api_error_msg(String)api_customer_name(String)api_customer_email(String)
Snippet Code:
/**
* CXone Studio Snippet: External REST API Call
*
* Purpose: Fetches customer details from an external REST API and parses the JSON response.
*
* Inputs:
* - customerId (String): The ID of the customer to fetch.
*
* Outputs:
* - success (Boolean): True if the call succeeded, false otherwise.
* - error (String): Error message if failed.
* - name (String): Extracted customer name.
* - email (String): Extracted customer email.
*/
async function main() {
// 1. Retrieve Inputs
const customerId = context.variables.get('customerId');
// Validation
if (!customerId || customerId.trim() === '') {
return {
success: false,
error: 'Input variable customerId is empty or null.',
name: '',
email: ''
};
}
// 2. Define Configuration
// Replace this URL with your actual external API endpoint
const API_ENDPOINT = `https://jsonplaceholder.typicode.com/users/${encodeURIComponent(customerId)}`;
// Optional: Headers for external APIs requiring authentication
const headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
// Example: 'Authorization': `Bearer ${context.variables.get('mySecureApiKey')}`
};
try {
// 3. Execute HTTP GET Request
const response = await fetch(API_ENDPOINT, {
method: 'GET',
headers: headers
});
// 4. Handle HTTP Status Codes
if (!response.ok) {
let errorDetail = '';
try {
const errorBody = await response.json();
errorDetail = errorBody.message || JSON.stringify(errorBody);
} catch (e) {
errorDetail = await response.text();
}
throw new Error(`API returned status ${response.status}: ${errorDetail}`);
}
// 5. Parse JSON Response
const jsonData = await response.json();
// 6. Extract Specific Fields
// Using optional chaining (?.) to prevent runtime errors if fields are missing
const customerName = jsonData.name || 'N/A';
const customerEmail = jsonData.email || 'N/A';
// 7. Return Structured Output
return {
success: true,
error: '',
name: customerName,
email: customerEmail
};
} catch (error) {
// 8. Handle Exceptions (Network errors, JSON parsing errors, etc.)
console.error('Snippet Error:', error); // Logs to CXone Flow Logs
return {
success: false,
error: error.message || 'Unknown error occurred during API call.',
name: '',
email: ''
};
}
}
Flow Configuration Steps:
- Add Snippet Action: Drag the Snippet action into the Flow.
- Input Mapping: Map
customerIdfrom the session variable holding the ID. - Output Mapping:
- Map
output.successtosession.api_call_success. - Map
output.errortosession.api_error_message. - Map
output.nametosession.customer_name. - Map
output.emailtosession.customer_email.
- Map
- Decision Node: After the Snippet, add a Decision node checking
session.api_call_success.- If True: Proceed with using
session.customer_name. - If False: Log
session.api_error_messageand route to an error handling path.
- If True: Proceed with using
Common Errors & Debugging
Error: TypeError: fetch is not a function
- Cause: This is rare in modern CXone Studio environments but may occur in very old runtime versions.
- Fix: Ensure you are using the latest CXone Studio Designer. The runtime supports ES6+ and the
fetchAPI. If you are in a legacy environment, you may need to useXMLHttpRequest, but this is highly discouraged.
Error: SyntaxError: Unexpected token < in JSON at position 0
- Cause: The API returned an HTML page (e.g., a 404 error page or a login redirect) instead of JSON.
- Fix: Check the
response.statusbefore callingresponse.json(). Add a check forresponse.headers.get('content-type')to ensure it containsapplication/json.
Error: NetworkError when attempting to fetch resource
- Cause: The external API is unreachable, or the CXone cloud environment has network restrictions (e.g., IP whitelisting on the target server).
- Fix: Ensure the target API allows connections from NICE CXone IP ranges. If the API requires specific IP whitelisting, contact NICE Support for the list of outbound IPs for your region.
Error: Timeout
- Cause: The external API took longer than the CXone Snippet timeout (typically 10-30 seconds depending on configuration) to respond.
- Fix: Optimize the external API response time. If the call is expected to be long, consider using asynchronous patterns (e.g., webhook callbacks) instead of synchronous Snippet calls.
Error: Variable 'customerId' is not defined
- Cause: The input variable was not mapped in the Snippet Action configuration, or the session variable it references is null/empty at that point in the Flow.
- Fix: Verify the Input Mapping in the Snippet Action properties. Add a validation step in the Flow before the Snippet to ensure the variable is populated.