Send a Docusign Envelope from Zoho Creator with Deluge

Send Documents for Signature with the Docusign API from Zoho Creator

This function takes a Zoho Creator record, renders it to PDF, and sends it to a client for signature through Docusign — writing the envelope ID back onto the record so you can track it. Authentication runs through a Creator OAuth connection, so Zoho refreshes the token for you.

The original authentication scheme is being switched off. The 2017 version used Legacy Header Authentication — an X-DocuSign-Authentication header carrying a username, a password and an integrator key. Docusign is retiring it: originally slated for 30 September 2024, pushed through a warning phase, and per the May 2026 release notes the final deadline is now 30 September 2026 on both demo and production. Code written against it will stop working. The original also called /restapi/v2/login_information to find the account base URL, which is superseded by /oauth/userinfo, and used /restapi/v2/ — v2 has been in maintenance mode since February 2022 and gets no new features. This rewrite uses OAuth and v2.1 throughout.

Why this uses a connection instead of JWT Grant. Docusign recommends the JWT Grant flow for unattended server-to-server integrations, and for most languages that is the right advice. It does not work in Deluge: a Docusign JWT must be signed RS256, and Deluge has no RSA private-key signing primitive — zoho.encryption offers hashing, HMAC, AES and base64, but nothing that will sign with an RSA key. Rather than shipping a JWT example that cannot run, this uses a Zoho OAuth connection over the authorization-code flow. You authorise once in the browser, and Creator handles refresh from then on. It is less code and there is no token table to babysit.

Before you start

  • A Docusign integration key from the developer console, with a redirect URI pointing at Zoho.
  • A custom OAuth connection in Creator named docusign. Setup → Connections → Create Connection → Custom Service. Authorize URL https://account-d.docusign.com/oauth/auth, token URL https://account-d.docusign.com/oauth/token, scope signature.
  • A DS_Config form with Base_URI and Account_ID to cache the lookup.
  • Fields on the record: Client_Name, Client_Email, Contract_Name, plus DocuSign_Envelope_ID and DocuSign_Status to write back to.

Deluge function

// ============================================
// DOCUSIGN — SEND AN ENVELOPE FROM ZOHO CREATOR
// Auth is handled by a Creator OAuth connection named "docusign".
// ============================================

void DocuSign.sendEnvelope(int recordId)
{
CONN = "docusign";
AUTH_HOST = "https://account-d.docusign.com"; // production: account.docusign.com

// --- 1. Resolve the account's base URI. Do this once and cache it. ---
cached = DS_Config[ID != null] sort by Added_Time desc range from 0 to 1;
if(cached.count() > 0 && cached.Base_URI != null && cached.Base_URI != "")
{
baseUri = cached.Base_URI;
accountId = cached.Account_ID;
}
else
{
userInfo = invokeurl
[
url : AUTH_HOST + "/oauth/userinfo"
type : GET
connection : CONN
];

accounts = userInfo.getJSON("accounts");
if(accounts == null || accounts.size() == 0)
{
info "Docusign userinfo returned no accounts: " + userInfo.toString();
return;
}
acct = accounts.get(0); // or match on is_default == true
baseUri = acct.getJSON("base_uri");
accountId = acct.getJSON("account_id");

delete from DS_Config[ID != null];
insert into DS_Config
[
Added_User = zoho.loginuser
Base_URI = baseUri
Account_ID = accountId
];
}

// --- 2. Pull the document to sign out of Creator, as base64 ---
rec = Contracts[ID == recordId];
pdfFile = invokeurl
[
url : "https://creatorapp.zohopublic.com/YOUR_ACCOUNT/YOUR_APP/report/Contracts/" + recordId + "/pdf"
type : GET
connection : "creator_oauth_connection"
];
docBase64 = zoho.encryption.base64Encode(pdfFile);

// --- 3. Build the envelope ---
signHere = Map();
signHere.put("anchorString","/sig1/");
signHere.put("anchorUnits","pixels");
signHere.put("anchorXOffset","0");
signHere.put("anchorYOffset","0");
signHere.put("recipientId","1");
signHere.put("tabLabel","signer1sig");

signHereList = List();
signHereList.add(signHere);
tabs = Map();
tabs.put("signHereTabs",signHereList);

signer = Map();
signer.put("email",rec.Client_Email);
signer.put("name",rec.Client_Name);
signer.put("recipientId","1");
signer.put("routingOrder","1");
signer.put("tabs",tabs);

signerList = List();
signerList.add(signer);
recipients = Map();
recipients.put("signers",signerList);

document = Map();
document.put("documentBase64",docBase64);
document.put("documentId","1");
document.put("fileExtension","pdf");
document.put("name",rec.Contract_Name + ".pdf");

docList = List();
docList.add(document);

envelope = Map();
envelope.put("emailSubject","Please sign: " + rec.Contract_Name);
envelope.put("documents",docList);
envelope.put("recipients",recipients);
envelope.put("status","sent"); // "created" saves a draft instead

// --- 4. Send it. Note v2.1, not v2. ---
response = invokeurl
[
url : baseUri + "/restapi/v2.1/accounts/" + accountId + "/envelopes"
type : POST
parameters : envelope.toString()
headers: {"Content-Type":"application/json"}
connection : CONN
];

envelopeId = response.getJSON("envelopeId");
if(envelopeId != null)
{
rec.DocuSign_Envelope_ID = envelopeId;
rec.DocuSign_Status = response.getJSON("status");
info "Envelope sent: " + envelopeId;
}
else
{
info "Docusign error: " + response.toString();
}
}

Notes

  • Cache the base URI. Docusign issues each account a regional host — na3.docusign.net, eu.docusign.net and so on — and hardcoding the wrong one fails. /oauth/userinfo returns it, but that endpoint is rate-limited per hour per user and per integration key, so look it up once and store it. That is what DS_Config is for.
  • Anchor strings beat coordinates. anchorString places the signature wherever the literal text appears in the document — put /sig1/ in your Creator report template in white text and it lands correctly no matter how the content reflows. Absolute xPosition/yPosition breaks the first time a paragraph gets longer.
  • status is the send switch. "sent" delivers immediately; "created" leaves a draft in your Docusign account. Use "created" while testing.
  • Demo and production are different hosts and different keys. Promote the integration key through go-live before switching AUTH_HOST to account.docusign.com.

On scope: the original of this script was a client implementation carrying a few hundred lines of Deal Memo, Position and Employee logic, flattening event rows into template tabs. That has been left out deliberately — it was specific to one business and taught nothing about Docusign. What is above is the part that transfers: authenticate, resolve the account, build the envelope, send, record the ID.

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 →