Skip to content
SignYu
TemplatesPricingAPIDocsAboutBlogContact
  1. Home
  2. API
  3. Integrations
  4. Google Sheets

Send Aadhaar eSign Requests from Google Sheets

A spreadsheet of signers plus a folder of PDFs in Drive is how many small teams start. This guide adds an Apps Script to the sheet that sends each row's PDF to SignYu for Aadhaar eSign, writes the signing link back into the row, and refreshes the status on a timer.

Updated 2026-10-01

What you need

  • A Google Sheet with columns: Name, Phone, Email, Drive File ID, Document ID, Status, Sign Link.
  • The PDFs in Google Drive, readable by the account that runs the script.
  • A SignYu API key (starts with sk_live_). API access costs ₹999/month with a 3-day free trial; create the key under Developers in the dashboard.
  • Signature credits for your signers, from ₹15 per signature (₹15 per signature on packs of 10 or more). Sending uses one credit per signer.

Step 1: Store the key in Script Properties

Open Extensions, then Apps Script. Under Project Settings, add a script property SIGNYU_API_KEY. Anyone with edit access to the sheet can open the script, so share the sheet carefully.

Step 2: Send a row for signing

UrlFetchApp builds a multipart request automatically when the payload object contains a Blob. A Drive PDF's blob already has the application/pdf content type. muteHttpExceptions lets you read the error body instead of the script stopping.

const BASE = "https://signyu.com/api/v1";
const COL = { name: 1, phone: 2, email: 3, fileId: 4, docId: 5, status: 6, link: 7 };

function api_(method, path, options) {
  const key = PropertiesService.getScriptProperties().getProperty("SIGNYU_API_KEY");
  const res = UrlFetchApp.fetch(BASE + path, Object.assign({
    method: method,
    headers: { Authorization: "Bearer " + key },
    muteHttpExceptions: true,
  }, options || {}));
  const body = JSON.parse(res.getContentText() || "{}");
  if (res.getResponseCode() >= 300) {
    throw new Error(res.getResponseCode() + " " + body.error + ": " + body.message);
  }
  return body;
}

function sendRow_(sheet, row) {
  const v = sheet.getRange(row, 1, 1, 7).getValues()[0];
  if (v[COL.docId - 1]) return; // already sent

  const pdf = DriveApp.getFileById(v[COL.fileId - 1]).getBlob();
  const doc = api_("post", "/documents", { payload: { file: pdf, name: pdf.getName() } });

  api_("post", "/documents/" + doc.documentId + "/signers", {
    contentType: "application/json",
    payload: JSON.stringify({ signers: [{
      name: String(v[COL.name - 1]),
      phone: String(v[COL.phone - 1]).replace(/\D/g, ""),
      email: String(v[COL.email - 1]),
    }] }),
  });

  const sent = api_("post", "/documents/" + doc.documentId + "/send");
  sheet.getRange(row, COL.docId, 1, 3).setValues([[doc.documentId, sent.status, sent.signers[0].signUrl]]);
}

Step 3: Add a menu to send selected rows

A custom menu sends whichever rows are selected. Errors such as 402 insufficient_credits are written into the Status cell so you can see which rows failed.

function onOpen() {
  SpreadsheetApp.getUi().createMenu("SignYu")
    .addItem("Send selected rows", "sendSelected")
    .addItem("Refresh status now", "refreshStatus")
    .addToUi();
}

function sendSelected() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const range = sheet.getActiveRange();
  for (let r = range.getRow(); r < range.getRow() + range.getNumRows(); r++) {
    if (r === 1) continue; // header
    try {
      sendRow_(sheet, r);
    } catch (e) {
      sheet.getRange(r, COL.status).setValue("ERROR: " + e.message);
    }
  }
}

Verify webhooks

Apps Script web apps cannot read incoming request headers, so a doPost endpoint has no way to check the X-SignSetu-Signature header, and an unverified webhook should not change your data. Use a time-driven trigger instead: under Triggers, run refreshStatus every 10 minutes. It asks the API for each SENT row, which is authenticated with your key.

function refreshStatus() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
  const rows = sheet.getDataRange().getValues();
  for (let i = 1; i < rows.length; i++) {
    const docId = rows[i][COL.docId - 1];
    if (!docId || rows[i][COL.status - 1] === "COMPLETED") continue;

    const doc = api_("get", "/documents/" + docId);
    sheet.getRange(i + 1, COL.status).setValue(doc.status);

    if (doc.status === "COMPLETED") {
      // downloadUrl is temporary, so copy the signed PDF into Drive now.
      const signed = UrlFetchApp.fetch(doc.downloadUrl).getBlob().setName(docId + "-signed.pdf");
      const file = DriveApp.createFile(signed);
      sheet.getRange(i + 1, COL.link).setValue(file.getUrl());
    }
  }
}

Common mistakes

  • Sheets turns long numbers into numbers and may show them in scientific notation. Format the Phone column as plain text and strip non-digits before sending.
  • Each send uses one credit per signer. Running sendSelected twice on the same row is safe here because the Document ID check skips sent rows; remove that check and you will create duplicate documents.
  • Apps Script has daily UrlFetchApp quotas and a 6 minute run limit. Send large batches in chunks.
  • Do not call the downloadUrl through api_(), which adds your Bearer key; fetch it directly as shown.

Frequently asked questions

Do I need a Google Workspace account?

No. Apps Script works with a free Google account, though quotas are lower than on Workspace.

Can I generate the PDF from a Google Doc template first?

Yes. Copy the template with DriveApp, replace placeholders with DocumentApp, then call getAs("application/pdf") on the file and pass that blob as the file field.

Can one row have two signers?

Yes. Add more objects to the signers array, for example from extra columns. A document allows up to 6 signers, signing in the order you list them.

Why not use a webhook to update the sheet instantly?

Apps Script cannot read the signature header, so it cannot tell a real SignYu webhook from a forged one. Polling every 10 minutes with your API key is slower but trustworthy. For instant updates, put n8n or a small server in front.

API reference

  • Quickstart
  • Documents
  • Errors

Other integration guides

  • Aadhaar eSign API in Python with FastAPI Webhooks
  • Aadhaar eSign from Zoho Creator with Deluge
  • Aadhaar eSign Automation with n8n

Get your API key

Start a 3-day free trial of API access and send your first document today.

Start free trialSee API pricing and features
SignYu

Pay-per-use Aadhaar eSign for Indian businesses, landlords, and individuals. Sign PDFs in 2 minutes at ₹15 per signature.

LinkedIn →

Product

  • Aadhaar eSign
  • Pricing
  • Templates
  • Rent Agreement eSign
  • Verify Signature
  • eSign Quiz
  • API
  • API Docs

Company

  • About
  • eSign Guide
  • Blog
  • Press
  • FAQ
  • Contact
Powered by eMudhra (CCA-licensed ESP)·IT Act 2000 Compliant·Aadhaar OTP Authenticated·Made in India 🇮🇳

© 2026 BN Habitat Pvt Ltd·CIN: U45400CH2010PTC043443·GST: 03AAECB5185C1Z3

Regd. Office: H.NO. 3355, 2nd Floor, Sector 37-D, Chandigarh, Chandigarh - 160036

Op. Office: Office 34, 13th Floor, Sushma Infinium, Chandigarh Ambala Expressway, Zirakpur, Punjab - 140603

TermsPrivacyRefundCookie