Fixing INVALID_FUNCTION in CXone Studio Snippet: Correct Syntax for GetRESTProxy()

Fixing INVALID_FUNCTION in CXone Studio Snippet: Correct Syntax for GetRESTProxy()

What You Will Build

  • A CXone Studio Snippet that successfully executes an outbound HTTP request using the GetRESTProxy function without triggering an INVALID_FUNCTION runtime error.
  • This tutorial uses the NICE CXone Studio Snippet execution environment and internal platform APIs.
  • The language covered is JavaScript (ES5/ES6 compatible within the Studio Snippet sandbox).

Prerequisites

  • Environment: NICE CXone Studio.
  • Permissions: Access to the Studio environment with rights to create and deploy Snippets.
  • Knowledge: Understanding of CXone Studio Snippet lifecycle (Input/Output mappings, Execution context).
  • Dependencies: No external npm packages are required. The GetRESTProxy function is a native global object available within the Snippet execution context.

Authentication Setup

CXone Studio Snippets do not require manual OAuth token management for internal platform calls. The Snippet executes under the context of the authenticated user who triggered the flow (or the system context if automated).

When making external HTTP requests via GetRESTProxy, you must handle authentication headers manually in the request payload. For internal CXone API calls, the platform injects the necessary bearer token automatically if you use the correct internal endpoint patterns, or you must pass the token explicitly if calling external services.

This tutorial focuses on the syntax of the proxy object, which is the most common source of the INVALID_FUNCTION error. The error occurs because developers often attempt to instantiate the proxy incorrectly or call methods that do not exist on the returned object.

Implementation

Step 1: Understanding the GetRESTProxy() Signature

The INVALID_FUNCTION error typically arises from one of two mistakes:

  1. Calling GetRESTProxy as a constructor (e.g., new GetRESTProxy()). It is a factory function, not a class.
  2. Attempting to call .request() directly on the global GetRESTProxy instead of on the instance returned by it.

The correct signature is:
var proxy = GetRESTProxy();

This returns an object with a .request(config) method. The config object must adhere to a specific structure expected by the CXone runtime.

Step 2: Constructing the Valid Request Configuration

The config object passed to .request() is strict. Missing fields or incorrect types will cause silent failures or runtime errors.

Critical Fields:

  • url: String. The full endpoint.
  • method: String. HTTP method (GET, POST, PUT, DELETE). Must be uppercase.
  • headers: Object. Key-value pairs for HTTP headers.
  • body: String or Object. For POST/PUT, this contains the payload. If an object, it must be JSON-serialized by the proxy, but explicit stringification is safer.
  • timeout: Integer. Timeout in milliseconds.

Common Pitfall:
Developers often include contentType or accept as separate top-level properties. These must be inside the headers object.

// INCORRECT - Causes INVALID_FUNCTION or unexpected behavior
var config = {
    url: "https://api.example.com/data",
    method: "POST",
    contentType: "application/json", // WRONG: Not a top-level property
    headers: {
        "Authorization": "Bearer token"
    },
    body: { key: "value" }
};

// CORRECT
var config = {
    url: "https://api.example.com/data",
    method: "POST",
    headers: {
        "Authorization": "Bearer token",
        "Content-Type": "application/json" // CORRECT: Inside headers
    },
    body: JSON.stringify({ key: "value" }), // Explicit stringification is recommended
    timeout: 5000
};

Step 3: Executing the Request and Handling the Response

The .request() method is synchronous within the Snippet context but behaves like a blocking call. It returns a response object.

Response Object Structure:

  • status: Integer (e.g., 200, 404, 500).
  • body: String (The raw response body). You must parse this JSON manually.
  • headers: Object (Response headers).
  • error: String (If an error occurred during the network call).
try {
    // 1. Instantiate the Proxy
    var proxy = GetRESTProxy();

    // 2. Define Configuration
    var config = {
        url: "https://jsonplaceholder.typicode.com/posts/1",
        method: "GET",
        headers: {
            "Accept": "application/json"
        },
        timeout: 10000
    };

    // 3. Execute Request
    var response = proxy.request(config);

    // 4. Validate Status
    if (response.status >= 200 && response.status < 300) {
        // 5. Parse Body
        var data = JSON.parse(response.body);
        
        // Log success for debugging
        console.log("Success: " + data.title);
        
        // Return data for downstream use
        return {
            success: true,
            data: data
        };
    } else {
        console.error("HTTP Error: " + response.status + " - " + response.body);
        return {
            success: false,
            error: "HTTP " + response.status
        };
    }

} catch (e) {
    // This catches INVALID_FUNCTION or JSON parsing errors
    console.error("Snippet Error: " + e.message);
    return {
        success: false,
        error: e.message
    };
}

Complete Working Example

Below is a complete, copy-pasteable Snippet script. This example calls the public jsonplaceholder API to retrieve a user profile. It demonstrates proper error handling, header configuration, and JSON parsing.

Instructions:

  1. In CXone Studio, create a new Snippet.
  2. Set the Input parameters to empty (or define specific inputs if you want to parameterize the URL).
  3. Set the Output parameters to success (Boolean) and result (String/JSON).
  4. Paste the following code into the Script editor.
/**
 * CXone Studio Snippet: Safe GetRESTProxy Usage
 * 
 * Purpose: Demonstrates correct instantiation and usage of GetRESTProxy
 * to avoid INVALID_FUNCTION errors.
 * 
 * Input: None
 * Output: 
 *   - success (boolean): Whether the request succeeded
 *   - result (string): JSON string of the response body
 *   - statusCode (integer): HTTP status code
 */

// Define the target URL. 
// In production, replace this with a variable from Input mapping.
var targetUrl = "https://jsonplaceholder.typicode.com/users/1";

try {
    // STEP 1: Instantiate the REST Proxy
    // Note: GetRESTProxy is a global function. Do NOT use 'new'.
    var restProxy = GetRESTProxy();

    // STEP 2: Configure the Request
    var requestConfig = {
        // The full URL including protocol
        url: targetUrl,
        
        // HTTP Method (Must be uppercase)
        method: "GET",
        
        // Headers object
        headers: {
            "Accept": "application/json",
            "User-Agent": "CXone-Studio-Snippet/1.0"
        },
        
        // Timeout in milliseconds (Max usually 10000-30000 depending on org config)
        timeout: 5000
    };

    // STEP 3: Execute the Request
    // This is a blocking call. It returns a response object.
    var httpResponse = restProxy.request(requestConfig);

    // STEP 4: Handle the Response
    // Check for network-level errors first
    if (httpResponse.error) {
        throw new Error("Network Error: " + httpResponse.error);
    }

    // Check HTTP Status Code
    var statusCode = httpResponse.status;
    
    if (statusCode >= 200 && statusCode < 300) {
        // Success: Parse the body
        var responseBody = httpResponse.body;
        
        // Validate that the body is not empty before parsing
        if (!responseBody) {
            throw new Error("Empty response body received");
        }

        var parsedData = JSON.parse(responseBody);

        // Return structured output
        return {
            success: true,
            statusCode: statusCode,
            result: JSON.stringify(parsedData) // Serialize back to string for output mapping
        };

    } else {
        // HTTP Error (4xx, 5xx)
        console.error("HTTP Request Failed with Status: " + statusCode);
        console.error("Response Body: " + httpResponse.body);
        
        return {
            success: false,
            statusCode: statusCode,
            result: null
        };
    }

} catch (exception) {
    // STEP 5: Global Error Handling
    // This catches INVALID_FUNCTION, JSON.parse errors, or Network timeouts
    
    var errorMessage = exception.message || "Unknown Snippet Error";
    console.error("Snippet Exception: " + errorMessage);

    return {
        success: false,
        statusCode: 0,
        result: null
    };
}

Output Mapping Configuration:
After saving the script, map the output variables:

  1. success: Map to the success property from the script.
  2. statusCode: Map to the statusCode property from the script.
  3. result: Map to the result property from the script.

Common Errors & Debugging

Error: INVALID_FUNCTION

What causes it:
This is the most common error when using GetRESTProxy. It occurs when the runtime cannot find the function or the object structure is malformed.

  1. Typo in Function Name: GetRestProxy (lowercase ‘e’) vs GetRESTProxy.
  2. Incorrect Instantiation: Using new GetRESTProxy(). The function returns an object directly; it is not a constructor.
  3. Scope Issue: Attempting to call GetRESTProxy inside a nested function that does not have access to the global scope (rare in Studio Snippets, but possible if wrapped in strict IIFEs incorrectly).

How to fix it:
Ensure you are calling GetRESTProxy() exactly as shown:

// Correct
var proxy = GetRESTProxy();

// Incorrect
var proxy = new GetRESTProxy(); 
var proxy = GetRestProxy();

Error: TypeError: Cannot read property ‘request’ of undefined

What causes it:
This happens if GetRESTProxy() returns undefined. This is extremely rare but can occur if the Studio runtime is in a degraded state or if you are testing in a non-Snippet JavaScript environment (like a browser console).

How to fix it:
Verify that the code is running inside a CXone Studio Snippet node. GetRESTProxy is not available in standard JavaScript environments.

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

What causes it:
You called JSON.parse() on a response body that is HTML (usually an error page from the server) or empty.

How to fix it:
Check the response.body before parsing.

if (response.body && response.body.trim().length > 0) {
    var data = JSON.parse(response.body);
} else {
    console.warn("Response body is empty or invalid JSON");
}

Error: Timeout

What causes it:
The external server did not respond within the timeout period defined in the config.

How to fix it:
Increase the timeout value in the requestConfig. Note that CXone imposes a maximum timeout limit (often 10 seconds or 30 seconds depending on organization settings). If the endpoint is slow, consider optimizing the external API or using asynchronous patterns if supported by the downstream flow.

Official References