Functions allow users to program a set of operations and execute them when invoked from an application. Users can automate processes or integrate with Zoho and other third- party applications using functions.
Functions in Qntrl allow you to write your own scripts in a language that you are comfortable with. These are serverless functions, where the cloud provider allocates machine resources dynamically. You can write your code in Qntrl without having to worry about server management while running the code.
Qntrl supports multiple programming languages for writing functions:
Zoho Deluge
JavaScript
Python
Python 3
Java
Node.js
The supported languages vary depending on the module type selected.
Module Type | Purpose | Supported Languages |
Cards | Automate card field logic or business rules | Zoho Deluge (Only) |
Standalone | Custom scripts triggered manually or used in Circuits/Schedules | Deluge, Java, Python, Python 3, Node.js, Java Script |
Web Service REST | Used in inbound and outbound REST API calls | JavaScript |
Web Service SOAP | Used in inbound and outbound SOAP API calls | JavaScript |
Once in the editor:
Write your logic using the selected language.
Refer to the Languages section for guidance on configuring the chosen language.
Refer to the Configure Functions by Modules section to configure functions for different modules.
Configure the required parameters in the right panel.
Once your function is ready and the parameters are configured, click Save to store the function.
Click Save and Execute to test it with sample input.
If there are no errors, the Input dialog will open.
Whenever a function is executed, there will be some values passed with the function. These values are called arguments. Specify the arguments based on which your function runs in the dialog and click Execute.
The function will execute and render an Output in the Execution Status dialog box. This output will have two keys:
Output key with a value, which is the output data.
Log key has log data which the user prints using statement.
Click Deploy to bring it live and available for use.
In the list of functions, hover over the desired function and click the action menu (...).
The following actions are available:
Edit: Modify the function’s name and configuration settings.
Preview: View the function’s code without opening the editor.
REST API: Access the REST API link secured with OAuth credentials.
Delete: Permanently remove the function from your system.
Deluge functions is a native scripting language in Qntrl. No external packages are needed. It can be configured in Qntrl and linked to circuits, workflows, business rules, schedules, orchestrations, or used as standalone functions. Learn more about Zoho Deluge.
The function calls the public ipinfo.io API to retrieve geolocation details of the client based on their IP address.
The API returns information including IP, city, region, country, latitude-longitude coordinates, and organization/ISP.
The function extracts and displays these values for further use in applications like:
Location-based personalization (language, currency, offers).
Fraud detection (suspicious logins from unusual regions).
Logging and auditing user access.
If the request fails, an error message is logged for debugging.
Sample Deluge Code Snippet
void getUserGeoInfo() { api_url = "https://ipinfo.io/json"; response = invokeurl [ url :api_url type :GET ]; try { ip = response.get("ip"); city = response.get("city"); region = response.get("region"); country = response.get("country"); org = response.get("org"); loc = response.get("loc"); info "IP: " + ip; info "Location: " + city + ", " + region + ", " + country; info "Coordinates: " + loc; info "ISP/Org: " + org; } catch (e) { info "Error getting IP info: " + e.toString(); } }
Early Access
This feature is not enabled for all users. If you’d like to try it out, please email our support team for early access.
This function automates file management in Qntrl by creating a new folder at a specified path and uploading a file with the provided content.
function execute(data) {try {let jsonData = JSON.parse(data);if (!jsonData.folderName || !jsonData.filePath || !jsonData.fileContent) {console.error("Incomplete data provided.");return JSON.stringify({ success: false, message: "Incomplete data provided." });}let folderCreationResponse = OntrlFile.createFolder(jsonData.folderName, jsonData.filePath);folderCreationResponse.ifFailed(message => {console.error('Failed to create folder:', message);return JSON.stringify({ success: false, message: 'Failed to create folder.' });}).ifSuccess(() => {console.log('Folder created successfully.');let file = new File([jsonData.fileContent], 'uploaded_file.txt', { type: 'text/plain' });let uploadResult = OntrlFile.upload(file, {path: jsonData.filePath + '/' + jsonData.folderName,overwrite: true});console.log('Upload Result:', uploadResult);return JSON.stringify({ success: true, message: "Folder created and file uploaded successfully." });});} catch (error) {console.error('Error during execution:', error);return JSON.stringify({ success: false, message: "Error during execution." });}}
Sample Input
{"folderName": "ProjectDocs","filePath": "/user/uploads","fileContent": "Initial project requirements and specifications."}
Upon successful execution, a success message will be displayed, and the file will be uploaded to the newly created folder. If the execution is unsuccessful, an error message will be displayed.
Node.js functions can be created and configured in Qntrl with auto-packaging support. These functions can be associated with workflows, business rules, schedules, or orchestrations, or used as stand-alone functions.
This function validates whether the user-provided input is in a proper email format. It ensures only correctly structured email addresses are accepted before proceeding with further processing. This is particularly useful for input validation in workflows, forms, and user onboarding scenarios.
How It Works:
module.exports = async function(context, basicIO) { const input = basicIO.getParameter("email"); if(input === null) { basicIO.write(" provide a email paramter"); return; } const email = input.toString().trim(); const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const isValid = emailRegex.test(email); if (isValid) { basicIO.write("Valid email: " + email); context.log.INFO("Validated email: " + email); } else { basicIO.write("Invalid email format."); context.log.INFO("Email validation failed for input: " + email); } }
The input body must be a JSON object with values for the arguments used in the code.
Once executed, the given email format will be validated and returns either a success message with the email or an error message if the format is invalid.
Write your functions in Python and link them to workflows, business rules, schedules, and orchestrations, or use them as standalone logic. The code runs in a Python 2 environment. You should follow Python 2 syntax while using any features supported by Python 2.
This function validates the strength of a user-provided password. It ensures that the password meets standard security requirements such as minimum length, presence of uppercase and lowercase letters, numbers, and special characters. This can be useful for enforcing password policies in workflows or during user onboarding.
How It Works:
import re def check_password_strength(password): # Define regular expression patterns for strong passwords has_uppercase = re.compile(r'[A-Z]') has_lowercase = re.compile(r'[a-z]') has_number = re.compile(r'[0-9]') has_special = re.compile(r'[!@#$%^&*()_+{}\[\]:";\'<>?,./]') # Check if password meets all requirements if (has_uppercase.search(password) and has_lowercase.search(password) and has_number.search(password) and has_special.search(password) and len(password) >= 8): return True return False def runner(context, basicI0): password = basicI0.getParameter("password") is_strong = check_password_strength(password) basicI0.write(str(is_strong))
Packaged Files:
Configuration Keys
path: The .js file path that contains the function code.
action: Contains the action that your code performs. This is also the name of the main class in your .js file.
connector: Contains the name of the connection that your function calls, if any.
The input body must be a JSON object with values for the arguments used in the code as shown below.
Sample Input
{"password": "James@19189#"}
The function executes and displays the response in the console.
Java functions allow strong typing and are ideal for more structured automation.
Code your functions in Java and associate them with workflows, business rules, schedules, orchestrations, circuits, or have them as standalone functions.
This function converts amounts between currencies using live exchange rates from an external API. It helps automate quick financial calculations within workflows, avoiding manual conversions. For example, businesses can instantly convert an invoice in INR to its USD equivalent during transactions.
Sample Java Code Snippet
import com.zoho.cloud.function.Context; import com.zoho.cloud.function.basic.*; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import org.json.JSONObject; public class Java_doc1 implements ZCFunction { public void runner(Context context, BasicIO basicIO) throws Exception { String from = (String) basicIO.getParameter("from"); String to = (String) basicIO.getParameter("to"); String amountStr = (String) basicIO.getParameter("amount"); if (from == null || to == null || amountStr == null) { basicIO.write("Missing parameters: 'from', 'to', or 'amount'."); return; } double amount; try { amount = Double.parseDouble(amountStr); } catch (NumberFormatException e) { basicIO.write("Invalid amount. Please enter a valid number."); return; } // Call exchange rate API String apiUrl = String.format("https://free.ratesdb.com/v1/rates?from=%s&to=%s", from, to); URL url = new URL(apiUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("User-Agent", "Java"); int responseCode = conn.getResponseCode(); if (responseCode != 200) { basicIO.write("Failed to fetch exchange rate. HTTP code: " + responseCode); return; } BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); String inputLine; StringBuffer responseData = new StringBuffer(); while ((inputLine = in.readLine()) != null) { responseData.append(inputLine); } in.close(); // Parse JSON response JSONObject json = new JSONObject(responseData.toString()); JSONObject rates = json.getJSONObject("data").getJSONObject("rates"); if (!rates.has(to)) { basicIO.write("Exchange rate not available for currency: " + to); return; } double rate = rates.getDouble(to); double convertedAmount = amount * rate; String result = String.format("%.2f %s = %.2f %s", amount, from, convertedAmount, to); basicIO.write(result); } }
Only .jar files can be uploaded in the lib folder.
Files up to 10 MB are only allowed.
To pass the arguments of your function in the body, use the below code.
Sample Input
{"from": "INR","to": "USD","amount": "100"}
The function executes and displays the response in the console.
You can upload only one zip file per function.
The maximum allowed size of the zip file is 10MB.
Write your functions in Python and link them to workflows, business rules, schedules, and orchestrations, or use them as standalone logic. The code runs in a 3.9.16. version of the Python 3 environment. You should follow Python 3 syntax while using any features supported by Python 3.
This function evaluates the strength of a given password by checking its compliance with common security standards such as length, uppercase/lowercase letters, digits, and special characters.
How It Works:
The user inputs a password.
The function checks the following criteria:
Minimum length of 8 characters
At least one uppercase letter
At least one lowercase letter
At least one digit
At least one special character (!@#$%^&*(),.?":{}|<>)
Based on the evaluation, it returns:
Strong password if all conditions are met.
Moderate password if some conditions are missing.
Error message pointing out what is missing.
If the password is weak, the function suggests a randomly generated secure password.
Sample Python 3 Code Snippet
import re import secrets import string def runner(context, basicIO): context.log.INFO("log") password = basicIO.getParameter("password"); basicIO.write(check_password_strength(password)); def check_password_strength(password: str) -> None: strength = 0 if len(password) >= 8: strength += 1 else: return "Password should be at least 8 characters long." if re.search(r'[A-Z]', password): strength += 1 else: return "Password should include at least one uppercase letter." if re.search(r'[a-z]', password): strength += 1 else: return "Password should include at least one lowercase letter." if re.search(r'\d', password): strength += 1 else: return "Password should include at least one digit." if re.search(r'[!@#$%^&*(),.?":{}|<>]', password): strength += 1 else: return "Password should include at least one special character (!@#$%^&*(),.?\":{}|<>)" if strength == 5: return "Strong password!" elif 3 <= strength < 5: return "Moderate password. Try to include all types of characters." else: basicIO.write("Weak password. Consider using a stronger one.") suggestion = generate_secure_password() basicIo.write(f"Suggested strong password: {suggestion}") def generate_secure_password(length: int = 12) -> str: characters = string.ascii_letters + string.digits + "!@#$%^&*()?" return ''.join(secrets.choice(characters) for _ in range(length)) if __name__ == "__main__": pwd = input("Enter a password to check its strength: ") check_password_strength(pwd)
Packaged Files:
Qntrl automatically packages your Python function and creates config.json and library files.
In the left panel, you can view the config.json and lib files.
config.json is a configuration file
lib is the library to which you can upload your third-party packages. Right-click the folder to upload files.
Specify the values of the following keys:
path: The .js file path that contains the function code.
action: Contains the action that your code performs. This is also the name of the main class in your .js file.
connector: Contains the name of the connection that your function calls, if any.
Use the code below to pass the arguments of your function in the body.
Sample Input
"password": "sweri025377A"
The functions can be used in Circuits and Schedules.
Can be written in any supported language.
Must be deployed to be used.
Client Callable: Turn this on to allow the function to be called from browsers, widgets, and other backend functions.Turn it off to allow only backend functions to call it.
Manually define key-value parameters in the editor.
These values are passed during execution.
Each function should be packaged in a specific directory structure depending on the language used.
Depending on the selected language, the deployment package must be structured as follows:
Java
FunctionName (root folder)
|
|---- FunctionName.java // Runner file
|---- lib // Folder for for dependent .jar files
|---- <dependent .jar files>
|---- classes // Compiled class files in package structure
|---- <compiled dependent .class files in package structure>
Any .java files placed directly in the root folder (not within packages) will also be compiled.
To build Java functions using a custom IDE, download the zc-server-sdk-core.jar file and include it in your project setup.
Node.js
FunctionName (root folder)
|
|---- FunctionName.js // Runner file
|---- node_modules // Dependency folder
|-- <dependent js files & folders>
|
|---- FunctionName.py // Runner file
|---- <dependent.py files> // Additional modules or scripts
To include third-party libraries with your function, follow the enhanced deployment structure described below for supported languages.
Java (with Dependencies)
FunctionName(root folder)
|
| - - - - FunctionName.java // Main runner file
| - - - - config.json // Function configuration
| - - - - lib // Third-party JARs
| - - - - <dependent .jar files>
| - - - - classes
| - - - - <compiled dependent .class files in package structure>
FunctionName.java: Entry point of the function. You may define multiple runner files and configure them in config.json.
config.json: Contains metadata and execution settings for the function.
lib/: Place all third-party .jar files here.
classes/: Add your compiled .class files following the Java package structure.
Download Sample Java Deployment Zip
NodeJS (with Dependencies)
FunctionName(root folder)
|
| - - - - FunctionName.js // Main runner file
| - - - - config.json // Function configuration
| - - - - node_modules // Installed dependencies
| - - - - <third-party modules>
File Descriptions:
FunctionName.js: Primary script that executes the logic. Users can add multiple runners that can be configured in config.json.
config.json: Used to define runners and execution parameters.
node_modules/: This directory should have all third-party dependencies needed.
Download Sample Node.js Deployment Zip
Python / Python 3(with Dependencies)
FunctionName(root folder)
|
| - - - - FunctionName.py // Main runner file
| - - - - config.json // Function configuration
| - - - - lib // Third-party libraries
| - - - - <third-party modules>
File Descriptions:
FunctionName.py: Primary script that executes the logic. Users can add multiple runners that can be configured in config.json.
config.json: Defines runner configuration and dependencies.
lib/: Contains additional Python modules used by the function.
Functions created for web services support only JavaScript and are used in:
Inbound/Outbound REST APIs
Inbound/Outbound SOAP APIs
Use Codex SDK for script creation and refer to Codex documentation for schema references.
Key Configurations:
Module type must be set as Web Service REST or Web Service SOAP.
Scope (admin/user) defines execution privileges.
You are currently viewing the help articles of Qntrl 3.0. If you are still using our older version and require guidance with it, Click here.