Resolving INVALID_FUNCTION in CXone Studio: Correct GetRESTProxy() Syntax and Usage
What You Will Build
- A working CXone Studio Snippet that executes a synchronous HTTP GET request to an external API and parses the JSON response.
- This tutorial uses the NICE CXone Studio JavaScript Snippet engine.
- The implementation covers the correct instantiation of
GetRESTProxy(), handling of asynchronous responses via callbacks, and robust error handling for network and payload failures.
Prerequisites
- NICE CXone Studio Environment: Access to a CXone tenant with Studio enabled.
- Snippet Context: Understanding of how Studio Snippets execute within the flow (synchronous vs. asynchronous behavior).
- JavaScript Proficiency: Familiarity with ES6+ syntax, particularly arrow functions and JSON parsing.
- External API Endpoint: A publicly accessible REST API endpoint for testing (e.g.,
https://jsonplaceholder.typicode.com/posts/1).
Authentication Setup
CXone Studio Snippets run within a sandboxed Node.js environment. Unlike server-side integrations that require OAuth 2.0 client credentials flows, Studio Snippets execute with the permissions of the logged-in agent or the flow context.
However, if the external API you are calling requires authentication (e.g., an internal microservice requiring an API Key or JWT), you must handle this within the Snippet logic.
For this tutorial, we assume an external public API. If you need to call a protected CXone API from within a Snippet, note that GetRESTProxy() does not automatically inject the current user’s access token for external calls. You must manually retrieve the token using GetToken() or pass it as a flow variable if it was generated in a previous step.
Security Warning: Never hardcode API keys or secrets in Studio Snippets. Use CXone Configuration Variables or retrieve tokens dynamically.
Implementation
Step 1: Instantiating GetRESTProxy() Correctly
The INVALID_FUNCTION error typically occurs because GetRESTProxy is not a standard global JavaScript function. It is a specific helper object provided by the CXone Studio runtime. The most common syntax error is attempting to use await directly on the call or misinterpreting the callback structure.
The GetRESTProxy() function returns an object that contains methods like get(), post(), put(), and delete(). These methods are asynchronous and require a callback function to handle the response.
Incorrect Syntax (Causes INVALID_FUNCTION or TypeError):
// WRONG: Attempting to await the proxy object directly
const proxy = await GetRESTProxy();
// WRONG: Using modern fetch syntax which is not available in the sandbox
const response = await fetch(url);
Correct Syntax:
// CORRECT: Instantiate the proxy object
const restProxy = GetRESTProxy();
// CORRECT: Use the .get() method with a callback
restProxy.get(url, headers, body, callback);
Step 2: Configuring the Request and Handling the Callback
The get() method signature is:
restProxy.get(url, headers, body, callback)
- url: A string representing the full endpoint URL.
- headers: An object containing HTTP headers (e.g.,
Content-Type,Authorization). - body: For GET requests, this is typically
nullor an empty object{}. - callback: A function
(err, response) => { ... }that handles the result.
The response object passed to the callback has the following structure:
response.statusCode: HTTP status code (integer).response.body: The response body as a string.response.headers: The response headers object.
Step 2.1: Defining the Headers
Always set Content-Type to application/json if you expect JSON. If the external API requires specific headers, add them here.
const headers = {
"Content-Type": "application/json",
"Accept": "application/json"
// "Authorization": "Bearer " + token // Uncomment if auth is required
};
Step 3: Processing Results and Error Handling
The callback function is where you handle both success and failure. You must check for errors in the err parameter and validate the statusCode in the response object.
Critical Logic:
- Check if
erris not null. This indicates a network-level failure (DNS resolution failure, timeout, connection refused). - Check if
response.statusCodeis outside the 2xx range. This indicates an application-level failure (400, 401, 403, 404, 500). - Parse the
response.bodyusingJSON.parse(). Wrap this in a try-catch block because the body is always a string, and malformed JSON will throw a runtime error.
Code Example: The Callback Logic
const callback = function(err, response) {
if (err) {
// Network error
console.error("Network error occurred:", err);
SetOutputVariable("errorCode", "NETWORK_FAILURE");
SetOutputVariable("errorMessage", err.message);
return;
}
if (response && response.statusCode >= 200 && response.statusCode < 300) {
try {
// Parse JSON safely
const data = JSON.parse(response.body);
// Set output variables for the rest of the flow
SetOutputVariable("success", true);
SetOutputVariable("data", data);
// Example: Extract a specific field
if (data.title) {
SetOutputVariable("postTitle", data.title);
}
} catch (parseError) {
console.error("JSON Parse Error:", parseError);
SetOutputVariable("errorCode", "JSON_PARSE_ERROR");
SetOutputVariable("errorMessage", parseError.message);
}
} else {
// HTTP Error (4xx, 5xx)
console.error("HTTP Error:", response.statusCode);
SetOutputVariable("success", false);
SetOutputVariable("errorCode", "HTTP_ERROR_" + response.statusCode);
SetOutputVariable("errorMessage", response.body);
}
};
Complete Working Example
Below is a complete, copy-pasteable Studio Snippet. This snippet calls the JSONPlaceholder API to retrieve a single post. It demonstrates proper variable setup, proxy instantiation, callback handling, and output variable assignment.
Snippet Name: GetExternalPostData
// ============================================================================
// CXone Studio Snippet: GetExternalPostData
// Description: Retrieves data from an external REST API using GetRESTProxy()
// ============================================================================
// 1. Define Input Variables (Optional but recommended for flexibility)
// In Studio, map these to Flow Variables if needed
const apiUrl = "https://jsonplaceholder.typicode.com/posts/1";
const timeoutMs = 5000; // Note: GetRESTProxy does not expose timeout directly in basic syntax,
// but the runtime has a global timeout.
// 2. Initialize Output Variables
// These variables will be available in subsequent flow steps
SetOutputVariable("success", false);
SetOutputVariable("errorCode", null);
SetOutputVariable("errorMessage", null);
SetOutputVariable("postTitle", null);
SetOutputVariable("postBody", null);
// 3. Setup Headers
const headers = {
"Content-Type": "application/json",
"Accept": "application/json"
};
// 4. Instantiate GetRESTProxy
// This is the critical step that causes INVALID_FUNCTION if called incorrectly
const restProxy = GetRESTProxy();
// 5. Define the Callback Function
const apiCallback = function(err, response) {
// Handle Network Errors
if (err) {
console.error("REST Proxy Network Error:", err);
SetOutputVariable("success", false);
SetOutputVariable("errorCode", "NETWORK_ERROR");
SetOutputVariable("errorMessage", err.message || "Unknown network error");
return;
}
// Handle HTTP Responses
if (response) {
const statusCode = response.statusCode;
// Check for HTTP Success (2xx)
if (statusCode >= 200 && statusCode < 300) {
try {
// The body is always a string. Parse it.
const jsonData = JSON.parse(response.body);
// Set success outputs
SetOutputVariable("success", true);
SetOutputVariable("postTitle", jsonData.title);
SetOutputVariable("postBody", jsonData.body);
// Log success for debugging
console.log("Successfully retrieved post: " + jsonData.title);
} catch (e) {
// Handle JSON Parsing Errors
console.error("JSON Parse Error:", e);
SetOutputVariable("success", false);
SetOutputVariable("errorCode", "JSON_PARSE_ERROR");
SetOutputVariable("errorMessage", e.message);
}
} else {
// Handle HTTP Client/Server Errors (4xx, 5xx)
console.error("HTTP Error Code: " + statusCode);
SetOutputVariable("success", false);
SetOutputVariable("errorCode", "HTTP_" + statusCode);
SetOutputVariable("errorMessage", response.body || "No error body returned");
}
} else {
// Handle Null Response (Rare, but possible in some proxy configurations)
console.error("Null response received from proxy");
SetOutputVariable("success", false);
SetOutputVariable("errorCode", "NULL_RESPONSE");
SetOutputVariable("errorMessage", "The proxy returned a null response object");
}
};
// 6. Execute the Request
// Syntax: restProxy.get(url, headers, body, callback)
// Note: Body is null for GET requests
try {
restProxy.get(apiUrl, headers, null, apiCallback);
} catch (executionError) {
// Handle synchronous errors during proxy invocation
console.error("Proxy Invocation Error:", executionError);
SetOutputVariable("success", false);
SetOutputVariable("errorCode", "INVOCATION_ERROR");
SetOutputVariable("errorMessage", executionError.message);
}
Common Errors & Debugging
Error: INVALID_FUNCTION
What causes it:
This error occurs when the Studio runtime cannot find the GetRESTProxy function. This is almost always due to one of three reasons:
- Typo in the Function Name: JavaScript is case-sensitive.
Getrestproxy()orgetRESTProxy()will fail. It must beGetRESTProxy(). - Incorrect Execution Context: You may be trying to run this code in a standard JavaScript node or a custom script block that does not have access to the Studio runtime helpers. Ensure you are inside a “Snippet” node in the flow designer.
- Version Incompatibility: In very old versions of CXone Studio, the API might have been different. However,
GetRESTProxyhas been the standard for many years. If you are on an extremely legacy tenant, check with your NICE account team.
How to fix it:
- Verify the spelling:
G-e-t-R-E-S-T-P-r-o-x-y. - Ensure the code is inside a Snippet node, not a Condition or Assignment node.
- Check that the Snippet is saved and compiled without syntax errors before running the flow.
Error: TypeError: restProxy.get is not a function
What causes it:
You successfully instantiated the proxy, but the object returned is not what you expected. This can happen if GetRESTProxy() returns null or undefined due to internal runtime issues, or if you are mocking the function in a test environment incorrectly.
How to fix it:
Add a defensive check before calling .get():
if (!restProxy || typeof restProxy.get !== 'function') {
console.error("GetRESTProxy did not return a valid object");
SetOutputVariable("errorCode", "PROXY_INIT_FAILURE");
return;
}
Error: JSON Parse Error
What causes it:
The external API returned a string that is not valid JSON. This often happens if the API returns an HTML error page (e.g., a 404 page from a web server) instead of a JSON object.
How to fix it:
Always wrap JSON.parse() in a try-catch block as shown in the complete example. Additionally, log the response.body before parsing to inspect the content during debugging.
Error: Timeout
What causes it:
The external API takes longer to respond than the CXone Studio runtime allows. Studio Snippets have a maximum execution time (typically 5-10 seconds depending on configuration).
How to fix it:
- Optimize the external API response time.
- Reduce the size of the payload being fetched.
- If the operation is long-running, consider using an asynchronous pattern where the Snippet triggers the job and a webhook updates the flow later, rather than waiting for the response in the Snippet.