You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 11:55:33