Resolving INVALID_FUNCTION in CXone Studio: Correct Syntax for GetRESTProxy()

Resolving INVALID_FUNCTION in CXone Studio: Correct Syntax for GetRESTProxy()

What You Will Build

  • One sentence: You will create a CXone Studio Snippet that successfully executes an outbound HTTP GET request to a third-party API or internal service.
  • One sentence: This tutorial uses the NICE CXone Studio Snippet environment and the native GetRESTProxy() JavaScript function.
  • One sentence: The code is written in JavaScript (ES6+ syntax supported by the CXone runtime).

Prerequisites

  • Platform Access: You must have access to the NICE CXone platform with permissions to edit Studio Flows and Snippets.
  • API Key (Optional but Recommended for Testing): While Studio Snippets run in the context of the interaction, understanding the underlying REST structure helps. No external SDK installation is required because the code runs inside the CXone engine.
  • JavaScript Knowledge: Familiarity with asynchronous JavaScript, Promise handling, and JSON parsing.
  • Target Endpoint: A valid HTTP endpoint to test against (e.g., https://jsonplaceholder.typicode.com/posts/1).

Authentication Setup

CXone Studio Snippets run server-side within the CXone infrastructure. Unlike external scripts, you do not manage OAuth tokens manually in the snippet code. The snippet inherits the permissions of the interaction or the system user context, depending on how the flow is triggered.

However, if you are calling an external API that requires authentication, you must handle that authentication within the GetRESTProxy configuration. This tutorial assumes the target endpoint is public for demonstration. If your endpoint requires Basic Auth or Bearer tokens, you will inject those headers in the GetRESTProxy options object.

Critical Note on Context:
The GetRESTProxy function is only available within the Studio Snippet context. It is not available in standard Web Chat widgets or client-side JavaScript. Attempting to call it outside the CXone server-side execution environment will result in a ReferenceError.

Implementation

Step 1: Understanding the INVALID_FUNCTION Error

The INVALID_FUNCTION error in CXone Studio typically occurs for one of three reasons:

  1. Typo in Function Name: You typed GetRestProxy, getRESTProxy, or RESTProxy instead of GetRESTProxy. JavaScript is case-sensitive.
  2. Context Mismatch: You are trying to call this function in a context that does not support it (e.g., a custom HTML widget script rather than a Studio Snippet).
  3. Incorrect Argument Structure: The function signature is strict. Passing a string URL directly without the required options object, or passing an object with invalid keys, can trigger runtime validation errors that manifest as function invocation failures.

The Correct Signature:

var proxy = GetRESTProxy(url, method, options);

Where:

  • url: A string containing the full endpoint URL.
  • method: A string representing the HTTP method ("GET", "POST", "PUT", "DELETE").
  • options: An object containing headers, body, and timeout configurations.

Step 2: Constructing the GetRESTProxy Call

To avoid the INVALID_FUNCTION error, you must strictly adhere to the parameter types. The most common mistake is passing null or an empty object where a required field is expected, or misconfiguring the options object structure.

Below is the correct syntax for a GET request.

// Define the target URL
var targetUrl = "https://jsonplaceholder.typicode.com/posts/1";

// Define the HTTP Method
var httpMethod = "GET";

// Define the Options Object
// Even for GET requests, it is best practice to initialize headers
var requestOptions = {
    headers: {
        "Content-Type": "application/json",
        "Accept": "application/json"
    },
    timeout: 5000 // Timeout in milliseconds
};

// Invoke the function correctly
// Note: The function returns a Proxy object, not the response directly
var restProxy = GetRESTProxy(targetUrl, httpMethod, requestOptions);

Why this works:

  • We pass a valid string for url.
  • We pass a valid string for method.
  • We pass a valid object for options.
  • We assign the result to a variable. The GetRESTProxy function is synchronous in terms of creating the proxy object, but the execution of the request is asynchronous.

Step 3: Executing the Request and Handling the Response

This is where most developers encounter errors. The restProxy object created in Step 2 does not contain the response data. You must call .execute() on it. The .execute() method returns a Promise.

If you do not use await (within an async function) or .then(), the code will continue before the response arrives, leading to undefined values or race conditions.

// Ensure the snippet function is async if using await
// In CXone Studio, you typically define the main function as async

async function fetchExternalData() {
    try {
        var targetUrl = "https://jsonplaceholder.typicode.com/posts/1";
        var httpMethod = "GET";
        var requestOptions = {
            headers: {
                "Content-Type": "application/json"
            },
            timeout: 5000
        };

        // 1. Create the Proxy
        var restProxy = GetRESTProxy(targetUrl, httpMethod, requestOptions);

        // 2. Execute the Request (Returns a Promise)
        var response = await restProxy.execute();

        // 3. Check for HTTP Errors
        // The response object contains 'statusCode' and 'body'
        if (response.statusCode >= 400) {
            throw new Error("HTTP Error: " + response.statusCode + " - " + response.body);
        }

        // 4. Parse the Body
        // The body is returned as a string. Parse it to JSON.
        var jsonData = JSON.parse(response.body);

        // 5. Return the data for use in the Flow
        return jsonData;

    } catch (error) {
        // Log the error to the CXone logs for debugging
        log.error("Error executing REST Proxy: " + error.message);
        throw error; // Rethrow to halt the flow or handle in the Flow error handler
    }
}

Step 4: Handling POST Requests with Body Data

A common source of INVALID_FUNCTION or subsequent 400 Bad Request errors is misconfiguring the body for POST requests. The body must be a JSON string if you set Content-Type: application/json.

async function createExternalRecord() {
    try {
        var targetUrl = "https://jsonplaceholder.typicode.com/posts";
        var httpMethod = "POST";
        
        // The data to send
        var payload = {
            title: "foo",
            body: "bar",
            userId: 1
        };

        var requestOptions = {
            headers: {
                "Content-Type": "application/json",
                "Accept": "application/json"
            },
            body: JSON.stringify(payload), // CRITICAL: Must be a string
            timeout: 5000
        };

        var restProxy = GetRESTProxy(targetUrl, httpMethod, requestOptions);
        var response = await restProxy.execute();

        if (response.statusCode >= 400) {
            throw new Error("POST Failed: " + response.statusCode);
        }

        return JSON.parse(response.body);

    } catch (error) {
        log.error("POST Error: " + error.message);
        throw error;
    }
}

Complete Working Example

This is a full, copy-pasteable Studio Snippet script. In CXone Studio, create a new Snippet, paste this code, and ensure you define the output variables in the Snippet configuration to match the return values.

/**
 * CXone Studio Snippet: External API Integration
 * 
 * This snippet demonstrates the correct usage of GetRESTProxy
 * to avoid INVALID_FUNCTION errors and properly handle async responses.
 */

// Define the main execution function
// CXone Studio invokes this function when the snippet runs
async function main() {
    // 1. Define Input Variables (if any)
    // In a real scenario, these might come from the Flow as input parameters
    var inputId = "1"; 
    var baseUrl = "https://jsonplaceholder.typicode.com";

    // 2. Construct the URL
    var targetUrl = baseUrl + "/posts/" + inputId;

    // 3. Define Options
    var options = {
        headers: {
            "Content-Type": "application/json",
            "Accept": "application/json"
        },
        timeout: 10000 // 10 seconds
    };

    try {
        // 4. Initialize the REST Proxy
        // Correct Syntax: GetRESTProxy(url, method, options)
        var proxy = GetRESTProxy(targetUrl, "GET", options);

        // 5. Execute the Request
        var result = await proxy.execute();

        // 6. Validate HTTP Status
        if (result.statusCode >= 400) {
            // Handle 4xx and 5xx errors
            log.error("API Request failed with status: " + result.statusCode);
            log.error("Response Body: " + result.body);
            
            // Return a structured error object for the Flow to handle
            return {
                success: false,
                statusCode: result.statusCode,
                errorMessage: result.body
            };
        }

        // 7. Parse and Process Response
        var responseData = JSON.parse(result.body);

        // 8. Return Success Data
        return {
            success: true,
            data: responseData,
            title: responseData.title // Extracting specific field for convenience
        };

    } catch (exception) {
        // 9. Handle Runtime Exceptions (Network errors, JSON parse errors, etc.)
        log.error("Critical Error in Snippet: " + exception.message);
        log.error("Stack Trace: " + exception.stack);

        return {
            success: false,
            statusCode: 500,
            errorMessage: exception.message
        };
    }
}

// Expose the main function to the CXone runtime
// This is implicit in newer Studio versions, but explicitly calling it ensures clarity
main();

Common Errors & Debugging

Error: INVALID_FUNCTION

What causes it:

  • You spelled the function incorrectly.
  • You are calling GetRESTProxy from a client-side widget instead of a server-side Studio Snippet.
  • You passed an invalid type for one of the arguments (e.g., passing an object as the URL).

How to fix it:

  1. Verify the spelling: GetRESTProxy.
  2. Ensure the code is inside a Studio Snippet, not a Web Component or HTML block.
  3. Check that the first argument is a string, the second is a string, and the third is an object.

Code showing the fix:

// INCORRECT: Causes INVALID_FUNCTION or TypeError
GetRESTProxy(targetUrl); // Missing method and options

// INCORRECT: Wrong case
getRestProxy(targetUrl, "GET", options);

// CORRECT
var proxy = GetRESTProxy(targetUrl, "GET", options);

Error: undefined is not a function (at execute)

What causes it:

  • You called GetRESTProxy but did not assign it to a variable, or you assigned it incorrectly.
  • You tried to call .execute() on the response object instead of the proxy object.

How to fix it:

  • Ensure you capture the return value of GetRESTProxy.
  • Call .execute() on that return value.

Code showing the fix:

// INCORRECT
GetRESTProxy(url, "GET", options).execute(); // This might fail if GetRESTProxy returns null in some edge cases or if chaining is not supported directly without assignment in older runtimes

// CORRECT
var proxy = GetRESTProxy(url, "GET", options);
var response = await proxy.execute();

Error: JSON Parse Error

What causes it:

  • The API returned plain text, HTML (e.g., an error page), or an empty body, and you tried to parse it as JSON.

How to fix it:

  • Check result.body type or length before parsing.
  • Wrap JSON.parse in a try-catch block.

Code showing the fix:

var bodyStr = result.body;
var jsonData;
try {
    if (bodyStr && bodyStr.trim() !== "") {
        jsonData = JSON.parse(bodyStr);
    } else {
        jsonData = {}; // Default empty object
    }
} catch (e) {
    log.error("Failed to parse JSON: " + e.message);
    jsonData = { error: "Invalid JSON response" };
}

Official References