CXone Studio SNIPPET action — how to make a REST API call and parse the JSON response

CXone Studio SNIPPET action — how to make a REST API call and parse the JSON response

What You Will Build

  • You will build a CXone Studio Snippet that executes an HTTP GET request to an external REST API.
  • You will use the built-in http library within the Snippet runtime to handle authentication headers and JSON parsing.
  • You will cover JavaScript, the native language for CXone Studio Snippets.

Prerequisites

  • Platform: NICE CXone Studio (Flow Designer).
  • Component: Snippet Action (requires a Snippet definition in the CXone admin console or Studio library).
  • Language: JavaScript (ECMAScript 2020+ compatible).
  • Dependencies: No external npm packages are allowed. You must use the global http object provided by the Snippet runtime.
  • API Target: A public REST API endpoint for testing (e.g., https://jsonplaceholder.typicode.com/posts/1).

Authentication Setup

CXone Studio Snippets run in a secure, sandboxed Node.js-like environment. They do not execute browser-side JavaScript. Therefore, standard fetch or axios libraries are not available by default. Instead, CXone provides a global http object that wraps a secure HTTP client.

This client automatically handles TLS termination and proxy settings configured in your CXone environment. You do not need to configure OAuth tokens for the snippet runtime itself; the snippet runs with the permissions of the flow execution context. However, if the target API requires authentication, you must pass those credentials manually via headers.

The http Object Interface

The http object provides methods for standard HTTP verbs:

  • http.get(url, options)
  • http.post(url, options)
  • http.put(url, options)
  • http.delete(url, options)

Each method returns a Promise that resolves to a response object containing:

  • status: HTTP status code (integer).
  • headers: Object containing response headers.
  • body: String containing the raw response body.

Implementation

Step 1: Define the Snippet Structure and Inputs

A Snippet in CXone Studio acts as a reusable function. You must define inputs and outputs in the Snippet configuration UI, but the logic resides in the code editor.

For this tutorial, we will create a snippet named FetchExternalData.

  • Input: apiUrl (String) - The endpoint to call.
  • Input: authHeader (String) - Optional Bearer token.
  • Output: jsonData (Object) - The parsed JSON response.
  • Output: statusCode (Number) - The HTTP status code.

Here is the initial boilerplate for the Snippet code:

// Snippet: FetchExternalData
// Inputs: apiUrl, authHeader
// Outputs: jsonData, statusCode

// Initialize output variables to prevent undefined errors
var jsonData = {};
var statusCode = 0;

try {
    // Logic will go here
} catch (error) {
    // Error handling will go here
}

Step 2: Construct the HTTP Request

You must construct the request options object. The http library expects headers to be an object where keys are header names and values are strings.

If your target API requires a Bearer token, you must format the Authorization header correctly.

var options = {
    headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    },
    timeout: 5000 // Timeout in milliseconds
};

// Conditionally add authentication if provided
if (authHeader) {
    options.headers['Authorization'] = 'Bearer ' + authHeader;
}

Critical Note on Timeouts: The CXone Snippet runtime has a hard execution limit (typically 30 seconds total for the snippet). If your external API is slow, you must set a reasonable timeout in the options object to prevent the snippet from hanging and timing out the entire flow.

Step 3: Execute the Request and Handle the Promise

Since the http methods return Promises, you must use async/await or .then() chains. In CXone Studio Snippets, async functions are supported.

async function executeRequest() {
    try {
        var response = await http.get(apiUrl, options);
        
        statusCode = response.status;
        
        // Check for HTTP errors (4xx, 5xx)
        if (statusCode >= 400) {
            throw new Error('HTTP Error: ' + statusCode + ' ' + response.body);
        }
        
        return response;
    } catch (error) {
        // Re-throw to be caught by the main try-catch block
        throw error;
    }
}

// Execute the async function
var response = await executeRequest();

Step 4: Parse the JSON Response

The http library returns the body as a raw string. You must manually parse it using JSON.parse. This is a common failure point if the API returns empty bodies or non-JSON content types (like HTML error pages).

var bodyString = response.body;

// Validate that the body is not empty
if (!bodyString || bodyString.trim() === '') {
    jsonData = {};
} else {
    try {
        // Parse the JSON
        jsonData = JSON.parse(bodyString);
    } catch (parseError) {
        // If parsing fails, store the raw string or an error object
        jsonData = { error: 'Invalid JSON response', rawBody: bodyString };
        statusCode = 502; // Bad Gateway simulation for internal error
    }
}

Step 5: Assign Outputs to the Snippet Context

CXone Studio requires you to explicitly assign values to the output variables defined in the Snippet configuration. These variables must match the names defined in the UI exactly.

// Assign the parsed data and status code to the snippet outputs
output.jsonData = jsonData;
output.statusCode = statusCode;

Complete Working Example

Below is the complete, copy-pasteable code for a CXone Studio Snippet named FetchExternalData. This snippet accepts a URL and an optional auth token, fetches the data, parses the JSON, and returns the result.

/**
 * Snippet Name: FetchExternalData
 * Description: Makes a GET request to an external API and parses the JSON response.
 * 
 * Inputs:
 * - apiUrl (String): The full URL to request (e.g., https://api.example.com/data)
 * - authHeader (String): Optional Bearer token for authentication
 * 
 * Outputs:
 * - jsonData (Object): The parsed JSON object from the response
 * - statusCode (Number): The HTTP status code returned by the server
 */

var jsonData = {};
var statusCode = 0;
var errorMessage = '';

try {
    // 1. Validate Input
    if (!apiUrl || typeof apiUrl !== 'string') {
        throw new Error('Input apiUrl is required and must be a string.');
    }

    // 2. Configure Request Options
    var options = {
        headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'User-Agent': 'CXone-Studio-Snippet/1.0'
        },
        timeout: 5000 // 5 seconds timeout
    };

    // 3. Add Authentication if provided
    if (authHeader && typeof authHeader === 'string' && authHeader.trim() !== '') {
        options.headers['Authorization'] = 'Bearer ' + authHeader.trim();
    }

    // 4. Execute HTTP GET Request
    // Note: http.get returns a Promise
    var response = await http.get(apiUrl, options);

    statusCode = response.status;

    // 5. Handle HTTP Status Codes
    if (statusCode >= 400) {
        throw new Error('HTTP Request Failed with status ' + statusCode);
    }

    // 6. Parse JSON Body
    var bodyString = response.body;

    if (!bodyString || bodyString.trim() === '') {
        // Handle empty response gracefully
        jsonData = {};
    } else {
        try {
            jsonData = JSON.parse(bodyString);
        } catch (e) {
            throw new Error('Failed to parse JSON response. Raw body: ' + bodyString.substring(0, 100) + '...');
        }
    }

} catch (error) {
    // 7. Error Handling
    errorMessage = error.message || 'Unknown error occurred';
    statusCode = 500; // Default to internal server error for snippet failures
    jsonData = { error: errorMessage };
}

// 8. Assign Outputs to Snippet Context
// These variable names must match the outputs defined in the Snippet UI
output.jsonData = jsonData;
output.statusCode = statusCode;
output.errorMessage = errorMessage;

How to Configure in Studio

  1. Open CXone Studio.
  2. Navigate to Library > Snippets.
  3. Click Create Snippet.
  4. Name it FetchExternalData.
  5. In the Inputs tab:
    • Add apiUrl (Type: String).
    • Add authHeader (Type: String).
  6. In the Outputs tab:
    • Add jsonData (Type: Object).
    • Add statusCode (Type: Number).
    • Add errorMessage (Type: String).
  7. In the Code tab, paste the JavaScript code above.
  8. Click Save.

Using the Snippet in a Flow

  1. Drag the Snippet action into your flow.
  2. Select FetchExternalData from the dropdown.
  3. Map the inputs:
    • apiUrl: Map to a variable or set a constant like https://jsonplaceholder.typicode.com/posts/1.
    • authHeader: Map to a variable containing a token, or leave empty for public APIs.
  4. After the Snippet action, add a Set Variable or Log action to inspect {{snippet.jsonData}} and {{snippet.statusCode}}.

Common Errors & Debugging

Error: TypeError: http.get is not a function

Cause: You are testing the code in a local Node.js environment or a browser console instead of the CXone Studio Snippet runtime. The http object is injected globally only within the CXone Snippet execution context.

Fix: Ensure you are running the code inside a CXone Studio Snippet. Do not attempt to run this code locally with node index.js.

Error: SyntaxError: Unexpected token < in JSON at position 0

Cause: The API returned an HTML error page (e.g., a 404 Not Found or 500 Internal Server Error rendered as HTML) instead of JSON. JSON.parse fails on HTML.

Fix: Always check the Content-Type header of the response or the HTTP status code before parsing.

// Improved Parsing Logic
var contentType = response.headers['content-type'] || '';

if (statusCode >= 200 && statusCode < 300) {
    if (contentType.includes('application/json')) {
        jsonData = JSON.parse(response.body);
    } else {
        jsonData = { error: 'Expected JSON but received: ' + contentType };
    }
} else {
    jsonData = { error: 'HTTP Error ' + statusCode };
}

Error: TimeoutError or ETIMEDOUT

Cause: The external API took longer to respond than the timeout specified in the options, or the CXone network cannot reach the external IP.

Fix:

  1. Increase the timeout in the options object (e.g., 10000 for 10 seconds).
  2. Verify that the CXone environment allows outbound traffic to the target domain. CXone environments may have strict firewall rules. You may need to whitelist the external API’s IP address or domain in the CXone Admin Console under System Settings > Network.

Error: 401 Unauthorized or 403 Forbidden

Cause: The Authorization header was malformed or the token was invalid.

Fix:

  1. Ensure the token does not contain extra whitespace. Use .trim() when constructing the header.
  2. Verify the token format. If the API expects Basic auth, use Authorization: Basic <base64credentials>. If it expects Bearer, use Authorization: Bearer <token>.
// Debugging Tip: Log the header before sending
var authVal = 'Bearer ' + authHeader.trim();
console.log('Sending Auth Header: ' + authVal); // Note: console.log outputs to the Snippet execution log, visible in Studio Debug mode
options.headers['Authorization'] = authVal;

Error: ReferenceError: output is not defined

Cause: You are trying to assign values to output in a local test environment.

Fix: The output object is a global variable provided by the CXone Snippet runtime. It is only available during execution within Studio. Ensure your code is saved and executed via the Studio flow or the Snippet test runner.

Official References

ASSIGN rest_proxy = GetRESTProxy();
ASSIGN response = rest_proxy.Execute(“GET”, “https://api.example.com/user/123”, “”, “”);

// Check the actual status first to avoid silent failures
ASSIGN status_code = response.getStatusCode();

// The body is a string, not a parsed object. You have to decode it manually.
ASSIGN raw_body = response.getBody();
ASSIGN user_data = JSON.parse(raw_body);

// Now you can access perties normally
ASSIGN user_id = user_data.id;


The `Execute` method doesn't automatically deserialize the payload for you. It returns a generic response object where the body is just a raw string. Trying to access `.json` or direct perties on the response object will always fail because that method doesn't exist on the return type.

You need to pull the body string out using `getBody()` and then run it through `JSON.parse()`. I've burned hours on this exact issue in hybrid setups where the external API returns slightly malformed JSON or unexpected headers. Always check the status code first too. If the external call fails, `getBody()` might return an error message string, and `JSON.parse` will throw an exception that kills your snippet flow. Wrap it in a try/catch block if you can, or validate the status code is 200 before parsing.

Studio’s GetRESTProxy is a trap for anything beyond simple lookups. The response object returns a raw string, not a JSON object. You can’t just dot-notation into it. You’ll need to parse the string manually or use a Data Action if the logic gets complex.

Here’s how to handle it in Studio:

ASSIGN rest_proxy = GetRESTProxy();
ASSIGN response = rest_proxy.Execute("GET", "https://api.example.com/user/123", "", "");
ASSIGN status = response.getStatusCode();

IF status == 200
 ASSIGN raw_json = response.getBody();
 // Studio doesn't have a native JSON.parse in ASSIGN easily.
 // You usually have to push this to a Data Action or use a regex if it's simple.
 // For complex objects, Studio falls short.
ENDIF

If you’re doing this for custom channel routing or complex context enrichment, drop Studio. Use a DFO API webhook or a Lambda. Studio’s REST xy is limited by design. It’s fine for checking a status code, but parsing nested JSON payloads there is painful and ne to breaking on minor schema changes. Stick to code for anything that needs reliability.