如何用Google Apps Script对接DocuSign API?获取Token及发信封遇障求助
DocuSign API对接Google Apps Script问题修复
问题背景
已获取DocuSign的Integration Key并创建App Password,使用Google Apps Script编写了获取AccessToken的obtencionToken函数和发送信封的generarQuery函数,但均无法正常运行,以下是问题分析及修复方案。
一、获取AccessToken函数(obtencionToken)问题分析与修复
原代码
function obtencionToken() { var payload = { "grant_type": "password", "client_id": PropertiesService.getScriptProperties().getProperty('client_id'), "username": PropertiesService.getScriptProperties().getProperty('username'), ////The name of the app password I generated "password": PropertiesService.getScriptProperties().getProperty('password'), //The password of the app password I generated "scope": "api" } var data = generarQuery(payload) var params = { "method": 'post', "headers": { "content-type": "application/x-www-form-urlencoded", }, "payload": JSON.stringify(data), "muteHttpExceptions": true } var response = UrlFetchApp.fetch('https://demo.docusign.net/restapi/v2/oauth2/token', params); console.log(params); console.log(response); console.info(response.getResponseCode()) console.info(response.getContentText()) var access_token_response = JSON.parse(response).access_token; console.log("access_token_response: " + access_token_response) /* save token in Propertyservice */ PropertiesService.getScriptProperties().setProperty('token', access_token_response); return access_token_response; }
核心问题
- 用户名参数错误:
username应为你的DocuSign账号邮箱,而非App Password的名称,原注释有误。 - Payload格式错误:DocuSign的OAuth2 token接口要求
application/x-www-form-urlencoded格式,无需将payload转为JSON字符串,且错误调用了发送信封的generarQuery函数。 - 参数传递冗余:UrlFetchApp可直接将JSON对象自动编码为x-www-form-urlencoded格式,无需手动处理。
修复后的代码
function obtencionToken() { var payload = { "grant_type": "password", "client_id": PropertiesService.getScriptProperties().getProperty('client_id'), "username": PropertiesService.getScriptProperties().getProperty('username'), // DocuSign账号邮箱 "password": PropertiesService.getScriptProperties().getProperty('password'), // 生成的App Password "scope": "api" } var params = { "method": 'post', "headers": { "content-type": "application/x-www-form-urlencoded" }, "payload": payload, // 直接传入对象,UrlFetchApp自动编码 "muteHttpExceptions": true } var response = UrlFetchApp.fetch('https://demo.docusign.net/restapi/v2/oauth2/token', params); console.log(response.getResponseCode()); console.log(response.getContentText()); // 处理响应,判断是否成功获取token if (response.getResponseCode() === 200) { var access_token_response = JSON.parse(response.getContentText()).access_token; console.log("access_token_response: " + access_token_response); PropertiesService.getScriptProperties().setProperty('token', access_token_response); return access_token_response; } else { throw new Error("获取Token失败:" + response.getContentText()); } }
二、发送信封函数(generarQuery)问题分析与修复
原代码
function generarQuery(){ var payload = { //"documents": docs, "emailSubject": "Request a signature via email example", "templateId": "<TemplateID>", "recipients": { "signers": [ { "email": full_name, "name": email_address, "recipientId": "1", "routingOrder": "1", "pageNumbers": "1", "tabs": { "signHereTabs": [ { "anchorString": "Firma Solicitante", "anchorXOffset": "6.5", "anchorYOffset": "-0.2", "anchorIgnoreIfNotPresent": "false", "anchorUnits": "cms", } ], }, } ], }, "status": "sent" } var options2 = { "method": "post", "headers": { "Authorization": "Bearer"+ token2, "content-type": "application/json" }, "payload": JSON.stringify(payload), "muteHttpExceptions": true }; var token2 = UrlFetchApp.fetch('https://demo.docusign.net/restapi/v2/accounts/<AccountId>/envelopes', options2); var id_sobre = (JSON.parse(token2).envelopeId); console.log(payload); console.log(options2); console.log(id_sobre); console.info(token2.getResponseCode()) console.info(token2.getContentText()) Logger.log(token2) Logger.log("ID: " + id_sobre) return id_sobre; }
核心问题
- 变量顺序错误:
token2在使用后才定义,且错误将fetch结果赋值给token2,应先获取已保存的AccessToken。 - Authorization头格式错误:
Bearer与token之间缺少空格,正确格式为"Bearer " + token。 - 未定义变量:
full_name、email_address未定义,需传入或赋值。 - 占位符未替换:
<TemplateID>和<AccountId>需替换为实际的DocuSign模板ID和账号ID。 - 模板收件人逻辑错误:使用模板时,若模板已有收件人角色,应通过
roleName匹配,而非直接指定email和name(除非是新增收件人)。
修复后的代码
function sendEnvelope() { // 获取已保存的AccessToken var token = PropertiesService.getScriptProperties().getProperty('token'); if (!token) { // 如果没有token,先调用获取token函数 token = obtencionToken(); } // 定义收件人信息 var signerEmail = "收件人邮箱@example.com"; var signerName = "收件人姓名"; var templateId = "你的DocuSign模板ID"; var accountId = "你的DocuSign账号ID"; var payload = { "emailSubject": "请签署文档", "templateId": templateId, "templateRoles": [ // 使用模板角色匹配,而非直接recipients { "email": signerEmail, "name": signerName, "roleName": "模板中的角色名称", // 替换为你模板里的收件人角色名 "recipientId": "1", "routingOrder": "1" // 如果模板已定义签位置,无需重复添加tabs;若需要新增,保留tabs部分 /* "tabs": { "signHereTabs": [ { "anchorString": "Firma Solicitante", "anchorXOffset": "6.5", "anchorYOffset": "-0.2", "anchorIgnoreIfNotPresent": "false", "anchorUnits": "cms" } ] } */ } ], "status": "sent" }; var options = { "method": "post", "headers": { "Authorization": "Bearer " + token, // 注意Bearer后加空格 "content-type": "application/json" }, "payload": JSON.stringify(payload), "muteHttpExceptions": true }; var response = UrlFetchApp.fetch(`https://demo.docusign.net/restapi/v2/accounts/${accountId}/envelopes`, options); console.log(response.getResponseCode()); console.log(response.getContentText()); if (response.getResponseCode() === 201) { var envelopeId = JSON.parse(response.getContentText()).envelopeId; console.log("信封ID:" + envelopeId); return envelopeId; } else { throw new Error("发送信封失败:" + response.getContentText()); } }
额外注意事项
- 确保在Google Apps Script的
项目设置中,通过脚本属性添加client_id、username、password三个属性,值分别为你的DocuSign Integration Key、账号邮箱、App Password。 - DocuSign的Demo环境(demo.docusign.net)仅用于测试,正式环境需替换为
www.docusign.net。 - 若使用模板,必须确保
templateRoles中的roleName与模板中定义的收件人角色名称完全一致。
内容的提问来源于stack exchange,提问作者Alison Camila León
相关产品推荐
相关产品推荐

