如何利用DocuSign API处理嵌入式签署中的未完成合同?
处理DocuSign嵌入式签署的未完成合同流程与实现
DocuSign的预期处理逻辑
DocuSign会自动保留处于sent或delivered状态且签署人未完成全部操作的信封。你不需要手动保存未完成的签署进度,核心是在你的系统中关联用户与对应的DocuSign信封,当用户返回时,先查询是否存在未完成的关联信封,再决定是继续签署还是创建新信封。
具体实现步骤
建立用户与信封的关联存储
- 当首次为用户创建DocuSign信封时,在你的后端数据库中记录
用户ID与DocuSign信封ID的映射关系。 - 创建信封时,务必为签署人设置
clientUserId(值设为你的系统用户ID),这是后续匹配用户与收件人的关键标识。
- 当首次为用户创建DocuSign信封时,在你的后端数据库中记录
查询用户的未完成信封
- 用户返回网站点击签署按钮时,先通过用户ID从数据库取出关联的所有信封ID。
- 调用DocuSign的
Envelopes: getAPI查询每个信封的详情,判断是否满足:- 信封状态为
sent或delivered(未完成状态); - 对应用户的签署人记录中
completedDateTime为空(说明未完成签署)。
- 信封状态为
生成签署视图链接
- 若存在未完成信封:调用
Envelopes: createRecipientViewAPI,传入信封ID、用户的clientUserId及其他匹配的收件人信息,生成继续签署的视图链接。 - 若无未完成信封:执行原有流程创建新信封,记录关联关系后生成新的签署视图链接。
- 若存在未完成信封:调用
Node.js代码示例
1. 查询未完成信封
// 初始化DocuSign API客户端(需提前配置好认证信息) const docusign = require('docusign-esign'); const dsApiClient = new docusign.ApiClient(); dsApiClient.setBasePath('https://demo.docusign.net/restapi'); // 生产环境替换为正式域名 dsApiClient.addDefaultHeader('Authorization', `Bearer ${accessToken}`); const accountId = '你的DocuSign账户ID'; // 查询信封状态 async function getEnvelopeStatus(envelopeId) { const envelopesApi = new docusign.EnvelopesApi(dsApiClient); return envelopesApi.getEnvelope(accountId, envelopeId); } // 查找用户的未完成信封 async function findIncompleteEnvelope(userId) { // 从本地数据库获取用户关联的所有信封ID const userEnvelopes = await yourDb.query('SELECT envelope_id FROM user_envelopes WHERE user_id = ?', [userId]); for (const { envelope_id } of userEnvelopes) { const envelope = await getEnvelopeStatus(envelope_id); // 匹配当前用户的签署人记录,判断是否未完成 const currentSigner = envelope.recipients.signers.find(signer => signer.clientUserId === userId); if ((envelope.status === 'sent' || envelope.status === 'delivered') && currentSigner && !currentSigner.completedDateTime) { return envelope_id; } } return null; }
2. 生成签署视图链接
// 创建嵌入式签署视图(支持继续未完成信封) async function createSignerView(envelopeId, userId, userInfo, returnUrl) { const envelopesApi = new docusign.EnvelopesApi(dsApiClient); const viewRequest = { authenticationMethod: 'none', clientUserId: userId, // 必须与创建信封时的clientUserId一致 recipientId: '1', // 对应用户在信封中的recipientId,创建时需记录 returnUrl: returnUrl, userName: userInfo.name, email: userInfo.email }; const view = await envelopesApi.createRecipientView(accountId, envelopeId, { recipientViewRequest: viewRequest }); return view.url; }
3. 整合核心流程
async function handleSignRequest(userId, returnUrl) { // 1. 获取用户信息 const [userInfo] = await yourDb.query('SELECT name, email FROM users WHERE id = ?', [userId]); // 2. 查找未完成信封 const incompleteEnvelopeId = await findIncompleteEnvelope(userId); let signUrl; if (incompleteEnvelopeId) { // 继续未完成的签署 signUrl = await createSignerView(incompleteEnvelopeId, userId, userInfo, returnUrl); } else { // 创建新信封(复用你原有创建信封的逻辑) const newEnvelopeId = await createNewEnvelope(userId, userInfo); // 记录用户与新信封的关联 await yourDb.query('INSERT INTO user_envelopes (user_id, envelope_id) VALUES (?, ?)', [userId, newEnvelopeId]); // 生成新信封的签署链接 signUrl = await createSignerView(newEnvelopeId, userId, userInfo, returnUrl); } // 跳转至签署页面 res.redirect(signUrl); }
关键注意事项
- clientUserId的一致性:创建信封和生成视图时的
clientUserId必须完全一致,否则DocuSign无法匹配到对应的签署人。 - 信封状态校验:避免处理已完成(
completed)、作废(voided)或已过期的信封,确保只继续有效的未完成流程。 - 数据库关联的必要性:本地存储用户与信封的映射比直接通过DocuSign API查询更高效,也能避免同一用户多个信封的歧义问题。
内容的提问来源于stack exchange,提问作者Ry2254
相关产品推荐
相关产品推荐

