Send a Zoho Sign Document via Deluge in Zoho CRM

Wed Jan 22 2025
Zoho Sign · CRM · Automation

Send a Zoho Sign Document via Deluge in Zoho CRM

Two reliable ways to send documents for e-signature from CRM: (1) a Deluge task that uses your Zoho Sign connection, and (2) a raw REST call with invokeurl for full control. Both patterns include null-safety and basic error handling.

Mostafa Badawy··6 min read

Use Deluge Task when…

  • You’re sending from a known template and fields/roles are fixed.
  • You want simple, readable code with fewer moving parts.
  • Auth is already handled via a Connection in CRM/Creator.

Use invokeurl (REST) when…

  • You need endpoints/flags not exposed by a task.
  • You want custom headers, webhooks, reminders, or advanced recipients.
  • You’re troubleshooting requests with raw payloads/logs.

Pattern A — Deluge task (template-based send)

Fill recipients/roles and send directly from a Zoho Sign template.

// ====== Inputs (from CRM Deal/Contact etc.) ======
recId         = input.recordId;
primaryEmail  = ifnull(input.Primary_Email, "");
primaryName   = ifnull(input.Primary_Name, "");

// Guard against nulls
if (isNull(primaryEmail) || primaryEmail == "")
{
  return {"status":"error","message":"Missing recipient email"};
}

// ====== Template + signer role mapping ======
templateId = "<YOUR_TEMPLATE_ID>";   // e.g. from Zoho Sign template details
actions    = List();
signer     = Map();
signer.put("recipient_name", primaryName);
signer.put("recipient_email", primaryEmail);
signer.put("action_type", "SIGN");   // SIGN / APPROVE etc.
signer.put("recipient_role", "Client"); // must match template role
actions.add(signer);

// Optional notes / expiration / reminders
notes = "Please review and sign.";

// ====== Create a request from template (task) ======
// Depending on your environment, the task name may differ.
// Many accounts use: zoho.sign.createUsingTemplate(templateId, actions, notes);
resp = zoho.sign.createUsingTemplate(templateId, actions, notes);

// Basic success check
ok = !isNull(resp) && resp.containsKey("request_id");
info resp;
return if (ok) {"status":"ok","request_id":resp.get("request_id")} else {"status":"error","message":"Failed to create request"};
Tip: Ensure the recipient_role value exactly matches the role name defined in your Zoho Sign template. Mismatches are a common cause of “400 – invalid action/role”.

Pattern B — Raw REST with invokeurl

Use this when you need total control. The example below shows creating a request from a template and quick-sending it to one signer. Replace the host with your DC if needed (sign.zoho.eu,sign.zoho.in, etc.).

// ====== Build request payload ======
tmplId = "<YOUR_TEMPLATE_ID>";
payload = Map();
payload.put("templates", List().add(tmplId));
payload.put("request_name", "Service Agreement");

// Actions (recipients)
actions = List();
a1 = Map();
a1.put("recipient_name", ifnull(input.Primary_Name, ""));
a1.put("recipient_email", ifnull(input.Primary_Email, ""));
a1.put("action_type", "SIGN");
a1.put("recipient_role", "Client"); // must exist in the template
actions.add(a1);
payload.put("actions", actions);

// Quick-send without editing
payload.put("is_quicksend", true);

// Optional: notes, reminders, expire days, etc.
payload.put("email_remarks", "Please sign at your earliest convenience.");

// ====== Send via REST (Zoho Sign v1) ======
resp = invokeurl
[
  url        : "https://sign.zoho.com/api/v1/requests"
  type       : POST
  parameters : payload.toString()
  connection : "zohosign_oauth"  // set up OAuth-based Connection to Zoho Sign
];

// ====== Handle response safely ======
data = ifnull(resp.get("requests"), List());
info resp;
ok   = !isNull(resp) && resp.get("status") == "success";
return if (ok) {"status":"ok","response":resp} else {"status":"error","message":"Send failed","response":resp};

Mapping CRM data to template fields

If your template has fields to pre-fill (text/date/numeric), include a field_text_data map keyed by the field’s api_name. Keep the map small and null-safe.

fieldText = Map();
fieldText.put("Deal_Name", ifnull(input.Deal_Name, ""));
fieldText.put("Client_Company", ifnull(input.Account_Name, ""));

payload.put("field_text_data", fieldText); // attach before the invokeurl call

Error handling & common issues

  • Role mismatch: recipient_role must match the template role exactly.
  • Missing email/name: always ifnull inputs and stop early if empty.
  • Wrong DC: use sign.zoho.eu/.in/.com.au as appropriate.
  • 429 rate limits: add simple backoff if you send in bulk (sleep between requests).