Send a Fax from Zoho Creator with the RingCentral API and Deluge

Send Faxes with the RingCentral API from Zoho Creator

This function sends a fax from a Zoho Creator record through the RingCentral API: it authenticates, caches the access token so you are not re-authenticating on every call, pulls a PDF from a Creator report, and posts it to RingCentral as a multipart request.

Rebuilt from the ground up. The original no longer works. Two reasons. First, the original authenticated with grant_type=password — RingCentral retired the password grant (ROPC) on 31 March 2024, so that code now fails at the first call. It has been replaced with the JWT bearer flow, which is what RingCentral recommends for unattended server-to-server integrations. Second, the original did not post to RingCentral at all — it sent the request, including the bearer token, to a third-party PHP script over plain HTTP, and fetched the PDF through a second third-party relay. Both have been removed; this version calls RingCentral directly.

Before you start

  • A RingCentral app in the developer console with the JWT auth flow enabled and fax permissions granted. Generate a JWT credential there.
  • A Creator form named RC_Token with fields Access_Token (multi line), Expiry_Time (date-time), Added_User.
  • A Zoho OAuth connection for pulling the report PDF, named creator_oauth_connection.
  • Keep CLIENT_ID, CLIENT_SECRET and the JWT in Creator variables. They are shown inline below only so the example reads in one piece.

Deluge function

// ============================================
// RINGCENTRAL FAX FROM ZOHO CREATOR (JWT auth)
// Standalone function. Call from a button or workflow.
// ============================================

void ringcentral.sendFax(string faxNumber, string coverText, int recordId)
{
// --- Credentials. Store these as Creator variables, not inline. ---
CLIENT_ID = "YOUR_RINGCENTRAL_CLIENT_ID";
CLIENT_SECRET = "YOUR_RINGCENTRAL_CLIENT_SECRET";
JWT_CREDENTIAL = "YOUR_JWT_CREDENTIAL_FROM_THE_RC_CONSOLE";
API_SERVER = "https://platform.ringcentral.com";

// --- 1. Reuse a cached token if it is still good ---
accessToken = "";
cached = RC_Token[ID != null] sort by Added_Time desc range from 0 to 1;
if(cached.count() > 0 && zoho.currenttime < cached.Expiry_Time)
{
accessToken = cached.Access_Token;
}
else
{
// --- 2. JWT bearer flow. Replaces the retired password grant. ---
authHeaders = Map();
authHeaders.put("Authorization","Basic " + zoho.encryption.base64Encode(CLIENT_ID + ":" + CLIENT_SECRET));
authHeaders.put("Content-Type","application/x-www-form-urlencoded");

authBody = Map();
authBody.put("grant_type","urn:ietf:params:oauth:grant-type:jwt-bearer");
authBody.put("assertion",JWT_CREDENTIAL);

authResp = invokeurl
[
url : API_SERVER + "/restapi/oauth/token"
type : POST
parameters : authBody
headers: authHeaders
];

accessToken = authResp.getJSON("access_token");
if(accessToken == null || accessToken == "")
{
info "RingCentral auth failed: " + authResp.toString();
return;
}

expiresIn = authResp.getJSON("expires_in").toLong();
delete from RC_Token[ID != null];
insert into RC_Token
[
Added_User = zoho.loginuser
Access_Token = accessToken
Expiry_Time = zoho.currenttime.addSeconds(expiresIn - 300)
];
}

// --- 3. Fetch the PDF to fax, straight from Creator ---
pdfFile = invokeurl
[
url : "https://creatorapp.zohopublic.com/YOUR_ACCOUNT/YOUR_APP/report/Invoices/" + recordId + "/pdf"
type : GET
connection : "creator_oauth_connection"
];

// --- 4. Send the fax. multipart/form-data, direct to RingCentral. ---
faxHeaders = Map();
faxHeaders.put("Authorization","Bearer " + accessToken);

faxParams = Map();
faxParams.put("to",faxNumber);
faxParams.put("faxResolution","High");
faxParams.put("coverIndex",0);
faxParams.put("coverPageText",coverText);

faxResp = invokeurl
[
url : API_SERVER + "/restapi/v1.0/account/~/extension/~/fax"
type : POST
parameters : faxParams
files : pdfFile
headers: faxHeaders
];

msgId = faxResp.getJSON("id");
if(msgId != null)
{
info "Fax queued. Message id " + msgId + ", status " + faxResp.getJSON("messageStatus");
}
else
{
info "RingCentral fax error: " + faxResp.toString();
}
}

Notes

  • The token cache matters. RingCentral rate-limits the token endpoint hard. Authenticating on every fax will get you throttled. The RC_Token lookup re-uses a token until five minutes before it expires.
  • from is not yours to set. RingCentral picks the sending fax number from the extension’s outbound fax settings. Passing a from in the request does nothing.
  • Limits. 50 MB combined, 200 pages, and no special characters in attachment filenames — a filename with a comma or a slash will fail the whole request.
  • Sandbox first. Swap API_SERVER for https://platform.devtest.ringcentral.com while you are testing. Sandbox faxes do not send and do not bill.

Worth testing rather than trusting: Deluge’s handling of the files parameter alongside parameters in a multipart POST varies by Creator version. Run this against the RingCentral sandbox and read the response before wiring it to a production button. If your version rejects the combination, send the JSON body and the attachment as a hand-built multipart/mixed payload instead — RingCentral accepts both.

This script is part of the free Creator Scripts Deluge Library.

All 39 Deluge scripts, the full Zoho Creator course, and every downloadable asset are now free. Get free access →