Zoho Deluge Scripting: Custom Functions, Governance Limits, and Execution Constraints
How does Zoho Deluge scripting work - custom functions, governance limits, execution constraints?
TL;DR
- Bottom line: Deluge (Data Enriched Language for the Universal Grid Environment) is Zoho's proprietary scripting language embedded across 40+ Zoho products. Use it for automation, custom business logic, and integration via ~260 built-in integration tasks for 35 Zoho services plus invokeURL for third-party APIs.
- Key limit: 5,000 executed statements per function (loops multiply the count), 75 recursive function calls, and execution timeouts of 10s (buttons/validation), 30s (workflow), or 15min (scheduled). [src1, src3]
- Watch out for: Statement limits count by execution, not declaration -- a loop with 3 statements running 100 times consumes 300 of your 5,000 limit. This is the #1 cause of "execution limit exceeded" errors. [src1]
- Best for: Custom business logic inside Zoho apps -- workflow automation, data validation, cross-service integration, and scheduled batch operations. Not for compute-intensive processing or high-volume ETL.
- Authentication: Built-in integration tasks authenticate via Zoho's internal OAuth; invokeURL uses named "connections" with OAuth 2.0 for external APIs. [src4]
System Profile
Deluge is Zoho's proprietary scripting language embedded in their entire product ecosystem. Unlike traditional ERP scripting (Salesforce Apex, NetSuite SuiteScript), Deluge is shared across 40+ Zoho applications -- the same language works in CRM, Creator, Desk, Books, and every other Zoho product. This card covers the Deluge runtime as it applies to Zoho CRM and Zoho Creator (the most common contexts), but the core language and most governance limits are consistent across all Zoho products. Edition-specific limits (API credits, daily call quotas) vary by which Zoho product you are scripting in. [src6]
| Property | Value |
|---|---|
| Vendor | Zoho |
| System | Zoho Deluge Runtime (across Zoho One / CRM / Creator / 40+ apps) |
| API Surface | Deluge scripting language (integration tasks + invokeURL) |
| Current Version | Deluge 2.0 (current runtime) |
| Editions Covered | Standard, Professional, Enterprise, Ultimate, Zoho One |
| Deployment | Cloud |
| API Docs | Zoho Deluge Help |
| Status | GA |
API Surfaces & Capabilities
Deluge provides three primary mechanisms for integrating with external systems and other Zoho services. [src4, src6]
| API Surface | Protocol | Best For | Max Records/Request | Rate Limit | Real-time? | Bulk? |
|---|---|---|---|---|---|---|
| Integration Tasks | Zoho internal REST | Zoho-to-Zoho operations (CRM, Books, Desk, etc.) | Service-dependent | Counts as API credits | Yes | Limited |
| invokeURL | HTTPS (any method) | Third-party API calls, custom webhooks | 5 MB response (external), 15 MB (Zoho) | 2,000-5,000,000/day (edition) | Yes | No |
| Standalone Functions (REST API) | HTTPS POST | Exposing Deluge logic as API endpoints | 10 MB response, 95K chars body | Shares CRM API credit pool | Yes | No |
| Scheduled Functions | Internal trigger | Batch operations, periodic sync | N/A | 15-min execution window | No | Yes |
Rate Limits & Quotas
Per-Execution Limits
| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| Max statements executed | 5,000 | All Deluge functions | Loops multiply: 3 statements x 100 iterations = 300 consumed [src1] |
| Max recursive function calls | 75 | All Deluge functions | Nested function calls within a function [src1] |
| Max response size | 10 MB | Standalone functions (REST API) | Return value size limit [src3] |
| Max lines of execution | 200,000 | Zoho CRM functions | Higher than statement limit; counts include framework overhead [src2] |
| Max POST body size | 95,000 chars | Standalone functions | URL arguments capped at 5,000 chars [src7] |
| Max CRM fields per data transfer | 10 | Workflow custom functions | Data pushed to third-party apps [src5] |
Execution Timeouts by Trigger Type
| Trigger Type | Timeout | Notes |
|---|---|---|
| Custom button click | 10 seconds | User-facing, must be fast |
| Validation rule | 10 seconds | Synchronous, blocks record save |
| Related list | 10 seconds | Synchronous rendering |
| REST API (standalone function) | 10 seconds | External API callers expect quick response |
| Workflow rule (automation) | 30 seconds | Triggered by record create/update/delete |
| Blueprint transition | 30 seconds | Triggered during process stage changes |
| Scheduled function | 15 minutes | Background execution, longest timeout |
[src3]
Daily Limits (Rolling 24-Hour Window)
| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| sendmail (email) | 500/day (Deluge general), 50,000/day (CRM) | Email sending | CRM has higher allocation |
| invokeURL / getUrl / postUrl | 2,000/day (Deluge general), 5,000,000/day (CRM) | External API calls | CRM Enterprise/Ultimate have much higher limits |
| Integration tasks | 2,000/day (Deluge general) | Zoho-to-Zoho API calls | Each execution = 1 API credit consumed |
| SMS | 1,000,000/day | CRM SMS functions | Enterprise and above |
API Credit Limits by Edition (Zoho CRM)
| Edition | Base Credits | Per User License | Maximum | Notes |
|---|---|---|---|---|
| Standard | 5,000 | +200/license | 15,000 | Functions via Extensions only |
| Professional | 5,000 | +200/license | 20,000 | Functions via Extensions only |
| Enterprise / Zoho One | 20,000 | +500/license | 200,000 | Full function support |
| Ultimate / CRM Plus | 20,000 | +1,000/license | Unlimited | Scales with licenses |
Authentication
Deluge handles authentication differently depending on the integration type. [src4, src7]
| Flow | Use When | Token Lifetime | Refresh? | Notes |
|---|---|---|---|---|
| Built-in integration tasks | Zoho-to-Zoho operations | Managed by platform | Automatic | No explicit auth needed; uses logged-in user context or admin context |
| Connections (OAuth 2.0) | Third-party APIs via invokeURL | Managed by connection | Automatic refresh | Create in Settings > Connections; supports OAuth 2.0 for 100+ services |
| API Key | Exposing standalone functions as REST endpoints | Non-expiring (until regenerated) | N/A | Static key; admin-only regeneration |
| OAuth 2.0 (internal) | Sharing standalone functions within org | Standard OAuth token lifecycle | Yes | For internal organizational consumption |
Authentication Gotchas
- Connections are org-scoped, not user-scoped: A connection created by one admin is available to all functions in the org. If that admin is deactivated, the connection may break. Assign connections to service accounts. [src4]
- invokeURL connection parameter is a string: The connection name is passed as a text value (e.g.,
connection:"my_slack_connection"). Typos in the connection name silently fail -- there is no compile-time validation. [src4] - Integration tasks authenticate as the executing user: For workflow-triggered functions, the integration task runs as the record owner or workflow admin, not the user who caused the trigger. This can cause permission issues with role-based data access. [src5]
Constraints
- 5,000 statement execution limit is the #1 cause of failures: Loops executing over large record sets easily exceed this limit. A
for eachover 500 records with 10 statements inside = 5,000 statements exactly (the limit). [src1] - 10-second timeout on user-facing triggers: Custom buttons, validation rules, and related lists must complete in 10 seconds. Any invokeURL call to a slow API can cause timeout. [src3]
- invokeURL socket timeout is 40 seconds: Individual HTTP requests via invokeURL that take longer than 40 seconds will fail with a socket timeout error regardless of the function's overall timeout. [src4]
- 6 custom functions per workflow rule maximum: Only 1 instant action + 5 time-based actions allowed per workflow rule. [src5]
- Standard and Professional editions restrict functions to Extensions: Custom functions are not natively available in Standard/Professional Zoho CRM -- they require building or installing an Extension from Marketplace. [src2]
- No multi-threading or async execution within Deluge: All statements execute sequentially. There is no parallel processing within a single function execution. Large batch operations must be chunked across scheduled functions. [src6]
Integration Pattern Decision Tree
START -- User needs to script in Zoho Deluge
|-- What kind of operation?
| |-- Zoho-to-Zoho (e.g., CRM to Books, CRM to Desk)
| | |-- Is there a built-in integration task?
| | | |-- YES --> Use integration task (zoho.crm.*, zoho.books.*, etc.)
| | | | Simplest approach, pre-built wrappers, 1 API credit each
| | | |-- NO --> Use invokeURL with Zoho API + connection
| |-- Zoho-to-third-party (e.g., CRM to Slack, Stripe, custom API)
| | |-- Set up OAuth connection in Settings first
| | |-- Use invokeURL with connection parameter
| | |-- Response > 5 MB? --> Cannot process in Deluge; use middleware
| |-- Internal logic only (calculations, validations, field updates)
| |-- No API calls needed
| |-- Watch statement limit (5,000) for complex logic
|-- How will it be triggered?
| |-- User action (button click, validation) --> 10s timeout
| |-- Automation (workflow, blueprint) --> 30s timeout
| |-- Scheduled (periodic batch) --> 15min timeout
| |-- External system (REST API) --> 10s timeout, expose as standalone
|-- Data volume?
| |-- < 500 records per execution --> OK for single function
| |-- 500-5,000 records --> Chunk into batches via scheduled functions
| |-- > 5,000 records --> Use Zoho CRM Bulk API (not Deluge)
|-- Error handling needed?
|-- YES --> Wrap in try-catch, log errors via info or integration tasks
|-- Critical failures --> sendmail alert + return error response
Quick Reference
| Task | Deluge Syntax | Notes |
|---|---|---|
| Get CRM record | zoho.crm.getRecordById("Leads", recordId) | Returns MAP; 1 API credit |
| Search CRM records | zoho.crm.searchRecords("Contacts", "Email:equals:" + email) | Returns LIST of MAPs |
| Create CRM record | zoho.crm.createRecord("Deals", dataMap) | Returns MAP with id |
| Update CRM record | zoho.crm.updateRecord("Accounts", recordId, updateMap) | Returns MAP |
| Delete CRM record | zoho.crm.deleteRecord("Leads", recordId) | Returns MAP |
| HTTP GET (external) | invokeurl [url: apiUrl type: GET connection: "conn"] | 5 MB response limit |
| HTTP POST (external) | invokeurl [url: apiUrl type: POST body: jsonStr headers: headerMap connection: "conn"] | Set Content-Type in headers |
| Send email | sendmail [from: zoho.adminuserid to: email subject: subj message: body] | 15 MB attachment limit |
| Log debug output | info variableName | Visible in execution logs |
| Error handling | try { ... } catch(e) { info e.message; } | e.lineNo for line number |
| Return value | return responseMap | 10 MB max for standalone functions |
| Loop (list) | for each item in myList { ... } | Each iteration counts as statements |
Step-by-Step Integration Guide
1. Create a custom function in Zoho CRM
Navigate to Setup > Developer Hub > Functions > + Create New Function. Name the function, add arguments, and write Deluge code in the editor. [src7]
// Function: updateAccountRevenue
// Arguments: accountId (bigint), newAmount (decimal)
accountMap = zoho.crm.getRecordById("Accounts", accountId);
currentRevenue = ifnull(accountMap.get("Annual_Revenue"), 0.0);
updatedRevenue = currentRevenue + newAmount;
updateMap = Map();
updateMap.put("Annual_Revenue", updatedRevenue);
response = zoho.crm.updateRecord("Accounts", accountId, updateMap);
info response;
return response;
Verify: Click "Save & Execute Script" with test argument values. Check the execution log for the info output.
2. Associate function with a workflow rule
Go to Setup > Automation > Workflow Rules > create a new rule. Set the trigger, add an instant action > Custom Function > select your function. Map arguments to CRM fields. [src5]
// Workflow-triggered function (30-second timeout)
// Argument mapping: accountId = ${Deals.Account_Name.id}
// newAmount = ${Deals.Amount}
accountMap = zoho.crm.getRecordById("Accounts", accountId);
currentRevenue = ifnull(accountMap.get("Annual_Revenue"), 0.0);
updatedRevenue = currentRevenue + newAmount;
updateMap = Map();
updateMap.put("Annual_Revenue", updatedRevenue);
zoho.crm.updateRecord("Accounts", accountId, updateMap);
Verify: Create or update a Deal matching the workflow criteria. Check the Account's Annual_Revenue field for the updated value.
3. Call an external API with invokeURL
Create a Connection first (Settings > Developer Space > Connections), then use invokeURL in your function. [src4]
// Call Slack webhook to notify on deal closure
slackUrl = "https://hooks.slack.com/services/T00/B00/xxx";
payload = Map();
payload.put("text", "Deal Won: " + dealName + " for $" + amount);
response = invokeurl
[
url: slackUrl
type: POST
parameters: payload.toString()
headers: {"Content-Type": "application/json"}
];
info response;
Verify: Check the Slack channel for the notification message. Check the execution log for the info output showing the API response.
4. Implement error handling with try-catch
Wrap external API calls and record operations in try-catch blocks to handle failures gracefully. [src8]
try
{
response = invokeurl
[
url: apiEndpoint
type: GET
connection: "my_api_connection"
detailed: true
];
statusCode = response.get("responseCode");
if (statusCode != 200)
{
info "API returned " + statusCode + ": " + response.get("responseText");
sendmail
[
from: zoho.adminuserid
to: "[email protected]"
subject: "Integration Error: API returned " + statusCode
message: "Response: " + response.get("responseText")
];
}
else
{
data = response.get("responseText").toJSONList();
for each record in data
{
recordMap = record.toMap();
// Process each record...
}
}
}
catch(e)
{
info "Error at line " + e.lineNo + ": " + e.message;
sendmail
[
from: zoho.adminuserid
to: "[email protected]"
subject: "Deluge Function Error"
message: "Line: " + e.lineNo + " Error: " + e.message
];
}
Verify: Deliberately provide an invalid URL to trigger the catch block. Check execution logs and email for error details.
Code Examples
Python: Call a Zoho CRM Standalone Function via REST API
# Input: Zoho CRM standalone function URL, API key or OAuth token
# Output: Function execution result
import requests
function_url = "https://www.zohoapis.com/crm/v2/functions/my_function/actions/execute"
params = {
"auth_type": "apikey",
"zapikey": "YOUR_API_KEY"
}
payload = {
"arguments": {
"accountId": "1234567890",
"newAmount": 5000.00
}
}
response = requests.post(
function_url,
params=params,
json=payload,
headers={"Content-Type": "application/json"}
)
if response.status_code == 200:
result = response.json()
print(f"Function result: {result}")
else:
print(f"Error {response.status_code}: {response.text}")
JavaScript/Node.js: Call Zoho CRM Function via OAuth
// Input: OAuth access token, function name, arguments
// Output: Function execution result
// npm install axios@1
const axios = require("axios");
const accessToken = process.env.ZOHO_ACCESS_TOKEN;
const functionName = "my_function";
async function callZohoFunction() {
const url = `https://www.zohoapis.com/crm/v2/functions/${functionName}/actions/execute`;
const response = await axios.post(url, {
arguments: {
accountId: "1234567890",
newAmount: 5000.00
}
}, {
params: { auth_type: "oauth" },
headers: {
Authorization: `Zoho-oauthtoken ${accessToken}`,
"Content-Type": "application/json"
}
});
console.log("Result:", response.data);
return response.data;
}
callZohoFunction().catch(console.error);
Deluge: Batch Processing with Statement Limit Awareness
// Input: Module name, list of record IDs to process
// Output: Count of successfully processed records
// IMPORTANT: This pattern avoids the 5,000 statement limit
module = "Contacts";
processedCount = 0;
errorCount = 0;
// Fetch max ~400 records (10 statements per iteration = 4,000 max)
contacts = zoho.crm.getRecords(module, 1, 200);
for each contact in contacts
{
try
{
email = ifnull(contact.get("Email"), "");
if (email != "")
{
updateMap = Map();
updateMap.put("Email_Verified", true);
zoho.crm.updateRecord(module, contact.get("id"), updateMap);
processedCount = processedCount + 1;
}
}
catch(e)
{
errorCount = errorCount + 1;
info "Error processing " + contact.get("id") + ": " + e.message;
}
}
info "Processed: " + processedCount + ", Errors: " + errorCount;
return {"processed": processedCount, "errors": errorCount};
Data Mapping
Deluge Data Types Reference
| Deluge Type | Description | Conversion Function | Gotcha |
|---|---|---|---|
| TEXT | String values | .toString() or toText() | Max length varies by context; no explicit limit documented |
| NUMBER | Integer/decimal | .toNumber() or toDecimal() | Division of integers returns integer (use toDecimal first) |
| BOOLEAN | true/false | .toBoolean() | Truthy/falsy coercion differs from JavaScript |
| DATE | Date without time | .toDate() | Format: yyyy-MM-dd; timezone depends on user settings |
| DATETIME | Date with time | .toDateTime() | Format: yyyy-MM-dd hh:mm; 24h format in API |
| LIST | Ordered collection | .toJSONList() | Zero-indexed; for-each creates new scope |
| MAP | Key-value pairs | .toMap() | Keys are case-sensitive; .get() returns null for missing keys |
| FILE | Binary file data | .toFile() | 50 MB max in Creator; fetched via invokeURL or getUrl |
Data Type Gotchas
- Null handling is inconsistent:
ifnull(value, default)is the safest way to handle nulls. Directly accessing a null value in an operation will throw a runtime error. Useifnull()orisBlank()checks before every operation on fetched data. [src5] - Date format in API calls vs Deluge: Zoho CRM API returns dates as
yyyy-MM-ddstrings, but Deluge date operations expect DATE type objects. Always convert with.toDate()before date arithmetic. [src5] - JSON parsing requires two steps: API responses come as TEXT. Convert to LIST with
.toJSONList(), then each element to MAP with.toMap(). Skipping the second step gives you TEXT elements that look like MAPs but fail on.get(). [src4] - Multi-select picklists are semicolon-delimited: When reading multi-select fields from CRM, values are joined with
;. When writing, also use;as delimiter. [src5]
Error Handling & Failure Points
Common Error Codes
| Code | Meaning | Cause | Resolution |
|---|---|---|---|
| EXECUTION_LIMIT_EXCEEDED | Statement limit (5,000) reached | Loop over large dataset | Reduce iteration count; chunk into scheduled batches |
| FUNCTION_CALL_LIMIT_EXCEEDED | 75 recursive calls exceeded | Deep recursion or circular function calls | Flatten recursive logic; use iteration instead |
| SOCKET_TIMEOUT | invokeURL timed out at 40s | External API too slow | Add timeout handling; use async webhook pattern instead |
| EXECUTION_TIME_EXCEEDED | Function exceeded trigger timeout | Complex logic in button/validation context | Move heavy logic to scheduled function or workflow |
| INVALID_DATA | Malformed data in API call | Wrong data type or missing required field | Validate all inputs with isBlank/ifnull before API calls |
| AUTHENTICATION_FAILURE | Connection OAuth token expired/revoked | Connection owner deactivated or token revoked | Re-authorize connection; use service account |
| DAILY_LIMIT_EXCEEDED | Daily API credit quota exhausted | Too many function executions in 24h window | Upgrade edition or optimize to reduce API calls per function |
| RESPONSE_SIZE_EXCEEDED | Response larger than 5 MB / 10 MB | Large API response or return value | Paginate API calls; reduce response payload |
Failure Points in Production
- Silent statement limit failures in workflows: When a workflow-triggered function hits the 5,000 statement limit, it silently stops execution. The workflow shows as "completed" but the function's logic was only partially executed. Fix:
Add a counter variable and check it periodically. Log completion status. Break large loops into smaller scheduled batches.[src1] - Connection owner leaves the company: OAuth connections are tied to the user who created them. If that user is deactivated, all functions using that connection fail. Fix:
Create connections using a shared service account that is never deactivated. Document which connections belong to which service account.[src4] - Daily credit exhaustion causes cascading failures: When API credits run out, ALL functions in the org stop working -- not just the one that consumed the credits. Fix:
Monitor credit usage via Zoho CRM admin dashboard. Set up alerts at 80% consumption.[src2] - invokeURL returns truncated response: When an external API returns more than 5 MB, invokeURL silently truncates the response. Parsing the truncated JSON then fails with cryptic errors. Fix:
Use API pagination parameters (limit, offset) to keep responses under 5 MB.[src4] - Timezone-dependent date comparisons: Deluge date functions use the executing user's timezone (or org default for workflows). Comparing dates across timezones produces unexpected results. Fix:
Always convert to a common timezone before comparison. Use zoho.currenttime for consistent operations.[src5]
Anti-Patterns
Wrong: Processing all records in a single loop
// BAD -- 1,000 records x 8 statements = 8,000 statements (exceeds 5,000 limit)
allContacts = zoho.crm.getRecords("Contacts", 1, 200);
for each contact in allContacts
{
email = contact.get("Email");
phone = contact.get("Phone");
company = contact.get("Company");
updateMap = Map();
updateMap.put("Processed", true);
updateMap.put("Last_Processed", zoho.currentdate);
zoho.crm.updateRecord("Contacts", contact.get("id"), updateMap);
info "Processed: " + contact.get("id");
// 8 statements per iteration -- exceeds limit quickly
}
Correct: Chunk processing across scheduled functions
// GOOD -- Process in batches of 100, stay within statement limits
batchSize = 100;
page = 1;
contacts = zoho.crm.getRecords("Contacts", page, batchSize);
for each contact in contacts
{
updateMap = Map();
updateMap.put("Processed", true);
zoho.crm.updateRecord("Contacts", contact.get("id"), updateMap);
// 3 statements per iteration = 300 total for 100 records
}
// For remaining records, trigger next batch via scheduled function
Wrong: No error handling on invokeURL calls
// BAD -- if API fails, function crashes with no logging
response = invokeurl
[
url: "https://api.example.com/data"
type: GET
connection: "example_api"
];
data = response.toJSONList();
for each item in data { /* process */ }
Correct: Wrap invokeURL in try-catch with detailed response
// GOOD -- capture status code, handle errors, log everything
try
{
response = invokeurl
[
url: "https://api.example.com/data"
type: GET
connection: "example_api"
detailed: true
];
if (response.get("responseCode") == 200)
{
data = response.get("responseText").toJSONList();
for each item in data
{
itemMap = item.toMap();
// Process safely
}
}
else
{
info "API Error: " + response.get("responseCode");
}
}
catch(e)
{
info "Exception: " + e.message + " at line " + e.lineNo;
}
Wrong: Hardcoding API credentials
// BAD -- credentials in script, breaks on environment change
apiKey = "sk_live_abc123def456";
response = invokeurl
[
url: "https://api.stripe.com/v1/charges"
type: POST
headers: {"Authorization": "Bearer sk_live_abc123def456"}
parameters: chargeMap
];
Correct: Use Zoho Connections for authentication
// GOOD -- OAuth managed by connection, no credentials in code
response = invokeurl
[
url: "https://api.stripe.com/v1/charges"
type: POST
parameters: chargeMap
connection: "stripe_production"
];
// Connection handles OAuth token refresh automatically
Common Pitfalls
- Confusing "statements" with "lines of code": A multi-line
sendmailblock counts as 1 statement. But afor eachloop multiplies ALL inner statements by iteration count. Fix:Count statements by tracing execution flow, not by counting lines. Use info to log a counter variable to verify.[src1] - Testing with small data, deploying with large data: A function that works with 10 records fails with 500 because it hits the 5,000 statement limit. Fix:
Always test with production-scale data volumes. Calculate: (statements_per_iteration x max_expected_records) < 5,000.[src1] - Assuming integration tasks are free: Every
zoho.crm.getRecordById(),zoho.crm.searchRecords(), etc. consumes 1 API credit. A function with 5 integration tasks running 1,000 times/day = 5,000 credits. Fix:Audit credit consumption. Batch operations where possible. Use searchRecords instead of multiple getRecordById calls.[src2] - Not checking for null/empty before operations: Deluge throws runtime errors on null values. Fix:
Use ifnull(value, default) for every value fetched from a record or API. Use isBlank() for text fields.[src5] - Using getUrl/postUrl instead of invokeURL: The older functions have fewer capabilities (no connection support, no detailed response). Fix:
Always use invokeURL for new development.[src4] - Ignoring the 6-function-per-workflow limit: Each workflow rule supports only 1 instant + 5 time-based custom functions. Fix:
Consolidate related logic into a single function. Use a dispatcher function that calls sub-functions.[src5]
Diagnostic Commands
// Check current API credit usage (Zoho CRM admin)
// Navigate to: Setup > Developer Hub > APIs > Dashboard
// Shows: credits consumed, remaining, per-function breakdown
// Debug a function: add info statements throughout
info "Step 1: Input received - accountId = " + accountId;
info "Step 2: Record fetched - " + recordMap;
info "Step 3: Before update - statement count approx: " + statementCounter;
// Test invokeURL with detailed:true to see full HTTP response
testResponse = invokeurl
[
url: "https://api.example.com/test"
type: GET
connection: "my_connection"
detailed: true
];
info "Status: " + testResponse.get("responseCode");
info "Headers: " + testResponse.get("responseHeader");
info "Body: " + testResponse.get("responseText");
// Check function execution logs
// Navigate to: Setup > Developer Hub > Functions > select function > Logs
// Shows: execution time, input arguments, output, errors
// Verify connection status
// Navigate to: Setup > Developer Space > Connections
// Shows: connection name, service, status (active/expired), last used
// Monitor scheduled function execution
// Navigate to: Setup > Automation > Schedules > History
// Shows: execution status, start/end time, errors
Version History & Compatibility
| Change | Date | Impact | Notes |
|---|---|---|---|
| Deluge 2.0 runtime (current) | 2020 | Platform upgrade | Improved performance, expanded built-in functions, wider product support |
| API credit system overhaul | 2024 | Credit calculation change | Tiered consumption for Java/Node.js functions; Deluge remains 1 credit/execution |
| invokeURL enhancements | 2024 | New capabilities | Added PATCH, OPTIONS methods; response-format and response-decoding parameters |
| Try-catch support expanded | 2023 | Error handling | Available across all Zoho products (previously limited to some) |
| 260+ integration tasks | 2025 | Expanded integrations | Coverage across 35 Zoho services |
| Scheduled functions 15-min timeout | 2023 | Increased limit | Enables longer-running batch operations |
When to Use / When Not to Use
| Use When | Don't Use When | Use Instead |
|---|---|---|
| Custom business logic inside any Zoho app (CRM, Creator, Desk, Books) | High-volume ETL processing (>5,000 records per batch) | Zoho CRM Bulk API or external ETL tool |
| Automating workflows between Zoho products (CRM to Books, Desk to CRM) | Compute-intensive operations (ML, image processing, heavy math) | External service via invokeURL + webhook callback |
| Quick integrations with third-party APIs (Slack, Stripe, custom endpoints) | Real-time processing requiring <1s latency on complex logic | External microservice with direct API integration |
| Scheduled data sync running under 15 minutes | Operations requiring more than 5,000 statement executions | Chunk across multiple scheduled functions or use external orchestration |
| Form validation and data enrichment on record save | Standard/Professional CRM editions without Extensions | Upgrade to Enterprise or use Zoho Flow for no-code automation |
Important Caveats
- Deluge governance limits (5,000 statements, 75 function calls) are enforced per-execution and cannot be increased by upgrading your edition. The only workaround is chunking logic across multiple function executions. [src1]
- Daily API credit limits vary dramatically by edition: Standard caps at 15,000/day while Ultimate is effectively unlimited. Hitting the daily limit stops ALL functions in the org, not just the offending one. [src2]
- The official documentation explicitly warns that published limits may change without notice: "The limits that are currently specified on this page may not be accurate." Always test against current runtime behavior. [src1]
- invokeURL response size limits differ by context: 5 MB for external domains, 15 MB for Zoho domains in Creator, and 10 MB for standalone function return values. These are not consistently documented across products. [src3, src4]
- Deluge is cloud-only with no on-premise runtime. All script execution happens on Zoho's infrastructure. There is no local development environment or offline testing capability beyond the built-in script editor. [src6]