为什么 docGenFormFields 值未生效,已发送的 envelope 仍显示占位符?
结论
应先创建草稿 envelope,读取草稿中的 DocGen 字段,再更新字段并生成文档,最后发送 envelope。
DocGen 有专用的字段读取和更新端点,需要在通过 POST /envelopes 创建草稿后调用。compositeTemplates 支持 DocGen,现有创建方式可以保留。DocuSign 官方的复合模板示例也采用这一流程。
当前请求使用 "status": "sent" 直接发送,并将 docGenFormFields 放在创建请求的根层级。HTTP 201 只表示 envelope 创建成功,不能说明占位符已完成替换。
为什么 textTabs 和 prefillTabs 没有效果
DocGen sender fields 用于在发送前生成文档正文,与签署界面的 tabs 是两套不同的机制。
textTabs的locked控制对应签署字段是否可编辑,不会解析文档中的 DocGen 占位符。prefillTabs是文档级预填字段,放在 signer 下会出现题述的PrefillTab not allowed for recipient错误。即使位置正确,也不能代替 DocGen 的文档生成步骤。文档级用法可参见官方 SDK 文档中的 createDocumentTabs。
要根据字段值生成正文,需要调用 DocumentGeneration:updateEnvelopeDocGenFormFields。
正确的 API 调用步骤
所有请求均使用以下基础地址:
https://demo.docusign.net/restapi/v2.1
每次请求都携带 Authorization: Bearer <ACCESS_TOKEN>;有 JSON 请求体时,设置 Content-Type: application/json。将 {accountId}、{envelopeId} 等占位内容替换为实际值。
1. 使用 compositeTemplates 创建草稿
POST /accounts/{accountId}/envelopes
保留请求体中的模板和角色映射,将 status 改为 "created",并移除根层级的 docGenFormFields:
{
"emailSubject": "Please sign this contract",
"status": "created",
"compositeTemplates": [
{
"compositeTemplateId": "1",
"serverTemplates": [
{
"sequence": "1",
"templateId": "3cfaca9c-ffd5-4c16-a416-992ca05317b0"
}
],
"inlineTemplates": [
{
"sequence": "2",
"recipients": {
"signers": [
{
"name": "John Doe",
"email": "signer@example.com",
"recipientId": "55136564",
"roleName": "test_signer"
}
]
}
}
]
}
]
}
将示例邮箱替换为实际收件人邮箱。保存响应中的 envelopeId,后续请求会用到它。
2. 读取草稿中的 DocGen 字段
GET /accounts/{accountId}/envelopes/{envelopeId}/docGenFormFields
对应方法是 DocumentGeneration:getEnvelopeDocGenFormFields。
从响应中确认以下信息:
docGenFormFields[].documentId:字段所属的 DocGen 文档。docGenFormFieldList[].name:更新字段时使用的名称。
更新请求必须使用当前草稿实际返回的 documentId。不要假定它是 "1",也不要用 compositeTemplateId 代替。
字段名称也以该响应为准。label、name 和 fullyQualifiedPath 含义不同。官方要求更新请求中的 name 与读取响应中的 name 一致,参见DocGen 字段读取与填充说明。
3. 更新字段并生成文档
PUT /accounts/{accountId}/envelopes/{envelopeId}/docGenFormFields?update_docgen_formfields_only=false
如果上一步确认两个字段属于同一文档,且返回的名称与题述一致,请求体可以写成:
{
"docGenFormFields": [
{
"documentId": "<DOCUMENT_ID_FROM_GET_RESPONSE>",
"docGenFormFieldList": [
{
"name": "AgreementParty_displayName_Z2bXgzv",
"value": "John Doe"
},
{
"name": "C_demo_field_value_1Xkjiv",
"value": "Test"
}
]
}
]
}
将 <DOCUMENT_ID_FROM_GET_RESPONSE> 替换为上一步返回的实际值。如果两个字段属于不同文档,应分别放入对应 documentId 的对象中。
update_docgen_formfields_only 决定是否同时更新文档:
| 参数值 | 行为 |
|---|---|
false 或省略 | 更新字段并更新文档 |
true | 只保存字段值,文档保持不变 |
需要立即替换正文占位符时,使用 false 或省略该参数。DocuSign 官方 Postman 集合说明了这两种行为的区别。
4. 检查生成结果,再发送
确认生成文档中的 {{Agreement Party}} 和 {{demo_field}} 已替换为预期文本后,再调用:
PUT /accounts/{accountId}/envelopes/{envelopeId}
{
"status": "sent"
}
这是官方支持的发送草稿 envelope方式。如果字段更新或文档检查失败,集成代码应停止发送,避免签署人收到仍带有占位符的文档。
模板和账户还需要检查什么
模板必须包含可供 DocGen 处理的 DOCX 文档及 sender field 定义。DocuSign 支持通过 Agreement Template Builder、Template Assistant for Word,以及规定的手动字段语法创建这些定义。正文中有 {{...}},并不表示字段元数据完整;isAceGenDocument: true 也不能证明文档已完成字段合并。
开发账户提供文档生成功能,生产账户则需要相应的 DocGen 权益,具体应向 DocuSign 确认。相关前提见官方文档生成说明。
如果按上述流程操作后,占位符仍未替换,可根据返回结果排查:
- 草稿字段接口没有返回目标字段:检查模板版本、DOCX 字段定义,以及创建 envelope 时是否替换了原来的 DocGen 文档。
- 字段存在但填值失败:检查
documentId与name是否来自当前草稿,而非其他模板或 envelope。 - 字段值已保存但正文未变化:确认没有使用
update_docgen_formfields_only=true,并检查生成响应和实际文档。
DocGen 成功生成的值会成为文档正文。签署人无法像编辑普通 text tab 那样修改这些值,因此无需再为它们设置 locked: true。
示例中的其他注意事项
原请求示例的第二个字段对象缺少结束的 },原样发送会产生 JSON 语法问题。不过,实际请求返回了 HTTP 201,排查应以实际发送的请求体和日志为准,不能将这处粘贴遗漏认定为占位符未解析的原因。
已经发送的 envelope 不适合直接套用上述草稿生成流程。排查时应新建草稿,完成字段填充和文档检查后再发送。
备注:内容仅供参考。
