Let's Talk Run the Diagnostic Diagnostic

Zoho Deluge invokeUrl: Call Any API From Zoho

invokeUrl is the Deluge task that calls a web API from any Zoho function. You give it a URL, a method, and optionally headers, a body, and a connection that holds the credentials. It returns the API's response to a variable. Every integration we build between Zoho and another system starts with it.

This guide covers the syntax, the patterns we use in production, and the limits worth knowing before you build. If you'd rather have someone build the integration, that's our API integration work.

Diagram of a Zoho Deluge invokeUrl call: the function sends url, type, headers, body, and connection; the connection adds the credentials; the API's reply comes back with responseCode, responseHeader, and responseText when detailed is true

invokeUrl syntax

Here's the full task, from Zoho's invokeUrl reference:

responseMp = invokeurl
[
	url :"https://api.example.com/v1/orders"
	type :POST
	headers:headerMp
	body:bodyMp.toString()
	connection:"example_api"
	detailed:true
];
Key Required What it does
url Yes The endpoint. Domains with user-created (self-signed) SSL certificates can't be called.
type No GET, POST, PUT, PATCH, DELETE, or OPTIONS. Defaults to GET.
headers No A map of headers. A Content-Type here overrides Zoho's default.
body No The payload: text, a file, or a map.
parameters No Form data, or query parameters on GET and DELETE. Can't be combined with body.
connection No The link name of a connection that adds authentication.
detailed No true returns the status code, headers, and text as a map.
response-format No FILE returns the response as a file. NONE ignores it.
response-decoding No Character set for the response. Defaults to UTF-8.

files also exists for multipart uploads in Zoho Creator. Outside Creator, Zoho recommends sending files in body with a multipart/form-data content type.

Zoho's older getUrl and postUrl functions still appear in a lot of inherited code. invokeUrl replaces both, so we convert them whenever we're already editing a function.

Store credentials in a connection, not in the code

A connection holds the login for a service. The function refers to it by name, and Zoho adds the authentication to each request. Nobody reading the function sees the key, and you can rotate the key without touching the code.

Zoho's connections documentation lists five authentication types for custom services: API Key, Basic, OAuth 1, OAuth 2, and AWS Signature Version 4. For an API key, you choose whether it travels as a header, a query string, or form data, and you name the parameter to match the API's docs.

One rule trips people up: connection: takes the link name as a literal in quotes. Put it in a variable and the function won't save.

// THIS SAVES
resp = invokeurl
[
	url :urlStr
	type :GET
	connection:"example_api"
];
// THIS DOES NOT: connection: NEEDS A LITERAL, NOT A VARIABLE
connStr = "example_api";
resp = invokeurl
[
	url :urlStr
	type :GET
	connection:connStr
];

If a script calls the same API in several places, repeat the name at each call and note it in a header comment.

POST JSON to another system

The most common pattern: something happens in Zoho, and another system needs to know. Here, a deal closes in Zoho CRM and the function posts a message to a Slack channel through an incoming webhook:

//
// WORKFLOW: DEAL CLOSED WON
// POSTS THE DEAL TO THE SALES CHANNEL IN SLACK
//
dealMp = zoho.crm.getRecordById("Deals",dealIdInt);
amountStr = ifnull(dealMp.getJSON("Amount"),0).toString();
msgStr = "Closed won: " + dealMp.getJSON("Deal_Name") + " for $" + amountStr;
bodyMp = Map();
bodyMp.put("text",msgStr);
headerMp = Map();
headerMp.put("Content-Type","application/json");
slackResp = invokeurl
[
	url :"https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
	type :POST
	headers:headerMp
	body:bodyMp.toString()
	detailed:true
];
info slackResp.getJSON("responseCode");

Two details matter. bodyMp.toString() sends the map as JSON text, and the Content-Type header tells the API it's JSON. If you pass the map without toString() and without the header, Zoho sends it as form data.

Check the response before you trust it

Without detailed:true, you get only the response body, and a failed call can look like data. With it, you get a map:

Key Contains
responseCode The HTTP status, such as 200, 401, or 429
responseHeader The response headers
responseText The body

We set detailed:true on every call that writes data or feeds a decision. Here's the pattern, with a retry for errors that are usually temporary and an email when it still fails:

Flowchart of invokeUrl error handling in Deluge: call with detailed true, use the data on a 2xx code, retry up to three times on a 5xx code, stop and log on a 4xx code, and send an alert email from the catch block

//
// GET AN ORDER FROM THE ERP, RETRY UP TO 3 TIMES ON A SERVER ERROR
//
try
{
	orderMp = Map();
	for each attemptInt in {1,2,3}
	{
		erpResp = invokeurl
		[
			url :"https://api.example.com/v1/orders/" + orderIdStr
			type :GET
			connection:"example_api"
			detailed:true
		];
		codeInt = erpResp.getJSON("responseCode");
		if(codeInt >= 200 && codeInt < 300)
		{
			orderMp = erpResp.getJSON("responseText").toString().toMap();
			break;
		}
		// 4XX MEANS THE REQUEST IS WRONG, SO RETRYING WON'T HELP
		if(codeInt < 500)
		{
			info "ERP REJECTED THE REQUEST: " + erpResp.getJSON("responseText");
			break;
		}
	}
	info orderMp;
}
catch(e)
{
	sendmail
	[
		from :zoho.loginuserid
		to :"admin@yourcompany.com"
		subject :"Error on ERP order lookup"
		message :"See error below <br> " + e
	]
}

Deluge has no while loop, so retries and pagination iterate over a short list. A 429 (too many requests) is better handled by moving the work to a scheduled function than by retrying immediately.

Page through results

Most APIs return results in pages. The same list trick works: loop over page numbers and stop when a page comes back empty.

//
// PULL ALL OPEN INVOICES FROM THE EXTERNAL BILLING SYSTEM, 100 PER PAGE
//
invoicesLst = List();
for each pageInt in {1,2,3,4,5,6,7,8,9,10}
{
	pageResp = invokeurl
	[
		url :"https://api.example.com/v1/invoices?status=open&per_page=100&page=" + pageInt
		type :GET
		connection:"example_api"
	];
	pageLst = ifnull(pageResp.getJSON("data"),List());
	if(pageLst.size() = 0)
	{
		break;
	}
	invoicesLst.addAll(pageLst);
}
info invoicesLst.size();

Ten pages is a ceiling, not a guess. If the API can return more, raise the list or run it as a scheduled function, which in Zoho CRM gets 15 minutes instead of 30 seconds.

Limits worth knowing

invokeUrl has its own limits, and the function running it has more. These are from Zoho's invokeUrl reference and Zoho CRM's function limits:

Limit Value
invokeUrl timeout 40 seconds, then a socket timeout error
File responses from Zoho domains 15 MB (outside Creator)
File responses from other domains 5 MB
Zoho CRM function, button or REST API trigger 10 seconds
Zoho CRM function, workflow, Blueprint, or approval trigger 30 seconds
Zoho CRM function, schedule 15 minutes
Zoho CRM invokeUrl requests per org per day 5,000,000
Zoho CRM lines of execution per function run 200,000

The daily cap is generous. The ones that shape a design are the run-time limits. A function behind a button has 10 seconds in total, so two slow API calls can use it up. Our post on why Zoho CRM feels slow covers what that looks like when a function runs on save.

Decision guide for connecting Zoho to another system: use built-in zoho integration tasks for Zoho apps, a workflow webhook action for a simple one-way notification, invokeUrl in a function when you need logic or a response, and a scheduled function for bulk or slow work

Do you need invokeUrl at all?

Not always. Check these first:

  • Calling another Zoho app? Deluge has built-in integration tasks such as zoho.crm.getRecordById and zoho.books.createRecord. They're shorter than building the API call yourself.
  • A one-way notification with no logic? Zoho CRM workflow rules include a webhook action that sends record data to a URL with no code.
  • A standard pairing like CRM and ChatGPT? Zoho Flow may already have the actions you need.

invokeUrl is the right choice when you need to transform data, read the response, chain calls, or talk to an API nobody has prebuilt a connector for.

When invokeUrl fails: what we check first

  • Error due to - '{0}' returned instantly. Look at the connection before the payload. In our experience this usually means the request never left Deluge, most often because the connection is missing a scope or needs re-authorizing. A real HTTP failure takes longer and logs a status code.
  • 401 or 403. The connection's token expired or lacks permission. Re-authorize it in Setup > Developer Hub > Connections.
  • Socket timeout. The API took more than 40 seconds. Ask for less data per call, or move the work to a schedule.
  • The API says the body is empty. You used parameters where the API expects a JSON body, or left out the Content-Type header.
  • The API only accepts allowlisted IPs. Zoho's calls come from Zoho's servers, not your office, so plan the allowlist before you build.

What we usually change in inherited integrations

  • Convert getUrl and postUrl to invokeUrl.
  • Move API keys out of the code and into connections.
  • Add detailed:true and a status check to every call that writes data.
  • Wrap integrations in try/catch with an email to whoever owns them.
  • Move bulk syncs from workflows to scheduled functions.
  • Replace one-call-per-record loops with the API's bulk endpoint where it has one.

Building an integration that lasts

A good Zoho integration has its credentials in a connection, checks every response, tells someone when it fails, and runs where it has enough time. That's the standard we build to on our API integration and process automation projects, and it's often what we fix on Zoho rescue work. If you have a system Zoho needs to talk to, tell us what it is.

Frequently asked questions

What is invokeUrl in Zoho Deluge?

invokeUrl is the Deluge task for calling a web API from a Zoho function. It supports GET, POST, PUT, PATCH, DELETE, and OPTIONS, and it returns the response to a variable. It does the job of the older getUrl and postUrl functions you still see in inherited code.

Can I use body and parameters in the same invokeUrl call?

No. Zoho does not allow both in one call. Use body for a JSON payload. Use parameters for form data, or for GET and DELETE, where Zoho sends them as query parameters in the URL.

How do I get the HTTP status code from invokeUrl?

Add detailed:true to the task. The response then comes back as a map with responseCode, responseHeader, and responseText, so you can check the status before you use the data.

What is the invokeUrl timeout in Zoho?

40 seconds. If the API takes longer, the task throws a socket timeout error. The function running it also has its own limit, which in Zoho CRM is 10 seconds for buttons, 30 seconds for workflows, and 15 minutes for scheduled functions.

Where should I store an API key for invokeUrl?

In a connection. Zoho connections support API Key, Basic, OAuth 1, OAuth 2, and AWS Signature Version 4 authentication, and the function refers to the connection by name, so the key never appears in the code.

Free Zoho Game Plan

Got a system Zoho needs to talk to?

Free 30-minute call. A one-page written plan afterward. No obligation.

  1. 01Book a 30-minute call. Pick a time that suits you. You talk with a senior Zoho expert, not a sales rep.
  2. 02Walk us through it. Your current Zoho setup or what you're planning, the processes that matter most, and where things break or slow down.
  3. 03Get your plan in writing. A one-page plan: what to fix or build first, a rough cost range, and which engagement fits. It's yours to keep whether you work with us or not.

Or send us a message