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

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

What You Will Build

  • This tutorial demonstrates how to correctly instantiate and configure the GetRESTProxy() object in NICE CXone Studio Snippets to avoid the INVALID_FUNCTION runtime error.
  • It uses the NICE CXone Studio Snippet execution environment (JavaScript/TypeScript based).
  • The code examples are written in JavaScript, the primary language for CXone Studio Snippets.

Prerequisites

  • Environment: NICE CXone Studio Designer.
  • Component: Studio Snippet (JavaScript).
  • Required Permissions: The user executing the snippet must have permissions to make outbound HTTP requests from the CXone platform (typically configured in the CXone Admin console under Security > API Access or similar network settings).
  • Knowledge: Basic understanding of JavaScript asynchronous programming (async/await) and JSON structure.

Authentication Setup

In CXone Studio Snippets, authentication for outbound REST calls is handled by the GetRESTProxy() object itself. You do not manually inject OAuth tokens into the header unless you are calling an external API that requires a specific bearer token not managed by CXone. For internal CXone APIs or external services that accept CXone’s default authentication context, the proxy handles the handshake.

If you are calling an external API that requires a pre-shared key or a static API key, you must configure the headers explicitly in the GetRESTProxy configuration object.

Critical Note: The INVALID_FUNCTION error often arises not from authentication failure, but from incorrect instantiation of the proxy object or passing invalid arguments to its methods.

Implementation

Step 1: Correctly Instantiating GetRESTProxy()

The INVALID_FUNCTION error typically occurs when developers attempt to call GetRESTProxy as a method on an undefined object, or when they pass parameters in the wrong order or format. The GetRESTProxy function is a global helper in the Studio Snippet context. It returns a promise or a proxy object depending on the specific SDK version, but in modern Studio Snippets, it is best treated as a factory function that returns a configured client.

The correct syntax requires passing a configuration object that defines the base URL, headers, and timeout.

// INCORRECT: This causes INVALID_FUNCTION
// let proxy = GetRESTProxy(url, headers); // Wrong argument structure
// let proxy = this.GetRESTProxy(); // 'this' is not the correct context for global helpers

// CORRECT: Instantiation with a configuration object
const restConfig = {
    baseUrl: "https://api.niceincontact.com",
    headers: {
        "Content-Type": "application/json",
        "Accept": "application/json"
        // If calling external API with API Key:
        // "Authorization": "Bearer YOUR_TOKEN" 
    },
    timeout: 5000 // milliseconds
};

// GetRESTProxy is a global function in the Snippet context
let restProxy = GetRESTProxy(restConfig);

Step 2: Executing the HTTP Request

Once the proxy is instantiated, you must use the correct HTTP verb methods (get, post, put, delete). These methods return promises. A common mistake leading to INVALID_FUNCTION is attempting to use the proxy synchronously or chaining promises incorrectly.

Here is the correct pattern for a POST request to an internal CXone API endpoint (e.g., creating a note on a contact).

async function createContactNote(contactId, noteText) {
    // Define the endpoint path relative to the baseUrl
    const endpoint = `/v1/interactions/contacts/${contactId}/notes`;
    
    // Define the payload
    const payload = {
        note: noteText,
        createdDate: new Date().toISOString()
    };

    try {
        // Execute the POST request
        // restProxy.post(path, body, headersOverride)
        const response = await restProxy.post(endpoint, JSON.stringify(payload));
        
        // Check response status
        if (response.statusCode >= 200 && response.statusCode < 300) {
            console.log("Note created successfully");
            return response.body;
        } else {
            console.error(`Failed to create note. Status: ${response.statusCode}`);
            throw new Error(`HTTP Error: ${response.statusCode}`);
        }
    } catch (error) {
        // Handle network errors or serialization errors
        console.error("Error during REST call:", error);
        throw error;
    }
}

Step 3: Handling Dynamic Headers and Content Types

The INVALID_FUNCTION error can also be triggered if the GetRESTProxy configuration is malformed. For example, passing a null header object or an invalid baseUrl (missing protocol) will cause the underlying engine to fail initialization.

Ensure the baseUrl always includes https://.

// Dynamic Configuration Example
function getDynamicProxy(targetUrl) {
    // Validation to prevent INVALID_FUNCTION due to malformed URL
    if (!targetUrl || !targetUrl.startsWith("https://")) {
        throw new Error("Invalid Base URL provided");
    }

    const config = {
        baseUrl: targetUrl,
        headers: {
            "Content-Type": "application/json"
        },
        timeout: 10000
    };

    return GetRESTProxy(config);
}

// Usage
async function callExternalService() {
    const proxy = getDynamicProxy("https://example.com/api");
    
    try {
        // GET Request
        const result = await proxy.get("/data");
        return result.body;
    } catch (err) {
        console.error("External call failed", err);
    }
}

Complete Working Example

Below is a complete, copy-pasteable Studio Snippet script. This script retrieves contact details from the CXone API using GetRESTProxy. It includes proper error handling, type checking, and the correct instantiation pattern to avoid INVALID_FUNCTION.

/**
 * Studio Snippet: Retrieve Contact Details via REST Proxy
 * 
 * This snippet demonstrates the correct usage of GetRESTProxy()
 * to fetch data from the CXone v1 API.
 */

// Global helper provided by CXone Studio Snippet runtime
// var GetRESTProxy; 

/**
 * Main entry point for the snippet
 * @param {object} context - The snippet context containing contact info
 */
async function main(context) {
    
    // 1. Extract Contact ID from context
    // In Studio, context usually contains 'contact' or 'interaction' objects
    const contactId = context.contact && context.contact.id;
    
    if (!contactId) {
        console.error("Contact ID is missing from context");
        return { success: false, error: "Missing Contact ID" };
    }

    // 2. Configure the REST Proxy
    // Critical: baseUrl must be a valid HTTPS URL
    const restConfig = {
        baseUrl: "https://api.niceincontact.com",
        headers: {
            "Content-Type": "application/json",
            "Accept": "application/json"
        },
        timeout: 5000 // 5 seconds timeout
    };

    try {
        // 3. Instantiate the Proxy
        // This is the step where INVALID_FUNCTION often occurs if syntax is wrong
        const restProxy = GetRESTProxy(restConfig);

        // 4. Define the Endpoint
        // Using v1 API for contact details
        const endpoint = `/v1/interactions/contacts/${contactId}`;

        // 5. Execute the GET Request
        // The post/get/put/delete methods return a Promise
        const response = await restProxy.get(endpoint);

        // 6. Process the Response
        if (response.statusCode === 200) {
            const contactData = JSON.parse(response.body);
            
            // Log the result to Studio Debug Console
            console.log("Successfully retrieved contact: " + contactData.id);
            
            // Return data for use in subsequent flows
            return {
                success: true,
                data: contactData,
                statusCode: response.statusCode
            };
        } else if (response.statusCode === 404) {
            console.warn(`Contact ${contactId} not found`);
            return {
                success: false,
                error: "Contact Not Found",
                statusCode: response.statusCode
            };
        } else {
            console.error(`Unexpected status code: ${response.statusCode}`);
            return {
                success: false,
                error: `API Error: ${response.statusCode}`,
                statusCode: response.statusCode
            };
        }

    } catch (error) {
        // Catch block for network errors, timeouts, or INVALID_FUNCTION
        console.error("Exception in REST Call:", error.message);
        
        // Check specifically for function instantiation errors
        if (error.message.includes("INVALID_FUNCTION") || error.message.includes("GetRESTProxy")) {
            console.error("Check GetRESTProxy syntax and configuration object");
        }

        return {
            success: false,
            error: error.message
        };
    }
}

// Execute the main function
main(context);

Common Errors & Debugging

Error: INVALID_FUNCTION

What causes it:
This error indicates that the JavaScript engine in the Studio Snippet runtime could not resolve the GetRESTProxy function or that the arguments passed to it did not match the expected signature.

How to fix it:

  1. Check for Typos: Ensure you are calling GetRESTProxy (case-sensitive). Do not call GetRestProxy or getRESTProxy.
  2. Verify Context: Do not call this.GetRESTProxy(). GetRESTProxy is a global function in the snippet scope.
  3. Validate Arguments: Ensure you are passing a single configuration object, not separate arguments.
    • Bad: GetRESTProxy("https://...", { headers: {} })
    • Good: GetRESTProxy({ baseUrl: "https://...", headers: {} })
  4. Check for Null Config: If the configuration object is null or undefined, the engine may throw this error. Ensure the object is fully constructed before passing it.

Error: Timeout or Network Failure

What causes it:
The baseUrl is unreachable, or the firewall between CXone and the target API is blocking the request.

How to fix it:

  1. Increase the timeout value in the configuration object.
  2. Verify that the baseUrl is publicly accessible or whitelisted in your CXone tenant’s network settings.
  3. Check the response.statusCode. If it is 0, it is likely a network connectivity issue rather than an HTTP error.

Error: JSON Parse Error

What causes it:
The response.body is not valid JSON, but you attempt to parse it or use it as an object.

How to fix it:
Always check the Content-Type of the response or wrap JSON.parse in a try-catch block.

let bodyData;
try {
    bodyData = JSON.parse(response.body);
} catch (e) {
    console.error("Response body is not valid JSON");
    bodyData = response.body; // Fallback to string
}

Official References