PAYATHON 2026

DocuSign composite templates 中的 prefill text tabs 如何赋值?

数据小许

如果模板中的字段确实是由发送方填写的 prefill tab,当前代码的赋值上下文就不对:signer.Tabs.TextTabs 操作的是 recipient tabs,无法更新文档级的 prefill tabs。

如果要保留 prefill 字段,可以先创建草稿 envelope,读取文档中的 prefill tabs,按实际 TabId 更新,再发送。如果只是需要程序提前填入公司名称,供收件人查看,也可以将模板字段改为普通 recipient Text tab,通过 inline template 赋值并设置 Locked = "true"。

为什么 TabLabel 一致仍然没有生效?

DocuSign 中,“提前填写字段值”和“字段类型是 prefill”是两个不同的概念:

字段归属赋值位置
普通 recipient Text tab某个 signer 或模板角色recipients.signers[].tabs.textTabs
发送方 prefill Text tab文档,不关联 recipient文档 tabs 中的 prefillTabs.textTabs

DocuSign 官方说明指出,prefill fields 不关联任何 recipient,字段值由发送方设置。参见 DocuSign prefill fields 说明。

把字段放到相同 recipient 上,或添加一个包含 signer.Tabs 的 inline template,都不会改变字段归属。即使 TabLabel 相同,也不能跨这两种上下文更新字段。

PreFillLegalCompanyName_GUID 只是 anchor string。名称中的 PreFill 前缀不能证明它是 prefill tab,应检查 API 返回的实际字段结构。

方案一:保留 prefill tabs,创建草稿后更新

这条路径适合仍需使用发送方字段的模板。

  1. 使用现有 composite templates 创建 envelope,将 Status 设为 "created"。
  2. 获取生成后的 envelope 的实际 document IDs。
  3. 调用 GetDocumentTabs,检查 PrefillTabs.TextTabs。
  4. 在目标文档内按 TabLabel 找到字段,再使用返回的 TabId 更新值。
  5. 确认填充值正确后,将 envelope 状态改为 "sent"。

DocuSign 开发者支持给出的 prefill 更新示例使用文档 tabs 接口,将更新体放在 prefillTabs.textTabs 下,并提供目标字段的 tabId。参见官方支持示例。

对应的 REST 请求为:

GET /v2.1/accounts/{accountId}/envelopes/{envelopeId}/documents/{documentId}/tabs

取得字段 ID 后更新:

PUT /v2.1/accounts/{accountId}/envelopes/{envelopeId}/documents/{documentId}/tabs
Content-Type: application/json
{
  "prefillTabs": {
    "textTabs": [
      {
        "tabId": "<tabId returned by GET>",
        "value": "Test Customer LLC"
      }
    ]
  }
}

C# 示例

以下示例假设 envelopesApi 已完成认证,envelopeDefinition 已包含现有的 composite templates 和收件人配置。documentId 必须取自生成后的 envelope。

using System;
using System.Linq;
using DocuSign.eSign.Model;

// 先创建草稿,避免收件人在赋值完成前收到文档。
envelopeDefinition.Status = "created";
var result = envelopesApi.CreateEnvelope(accountId, envelopeDefinition);
var envelopeId = result.EnvelopeId;

var documentTabs = envelopesApi.GetDocumentTabs(
    accountId, envelopeId, documentId);

var matches = documentTabs.PrefillTabs?.TextTabs?
    .Where(tab => string.Equals(
        tab.TabLabel,
        "LegalCompanyName",
        StringComparison.Ordinal))
    .ToList();

if (matches == null || matches.Count == 0)
{
    throw new InvalidOperationException(
        "No matching prefill text tab was found in the document.");
}

var update = new Tabs
{
    PrefillTabs = new PrefillTabs
    {
        TextTabs = matches.Select(tab => new Text
        {
            TabId = tab.TabId,
            Value = "Test Customer LLC"
        }).ToList()
    }
};

envelopesApi.UpdateDocumentTabs(
    accountId, envelopeId, documentId, update);

// 发送前重新读取,确认目标字段已更新。
var verified = envelopesApi.GetDocumentTabs(
    accountId, envelopeId, documentId);

var updatedIds = verified.PrefillTabs?.TextTabs?
    .Where(tab => tab.Value == "Test Customer LLC")
    .Select(tab => tab.TabId)
    .ToHashSet();

if (updatedIds == null ||
    matches.Any(tab => !updatedIds.Contains(tab.TabId)))
{
    throw new InvalidOperationException("Prefill verification failed.");
}

envelopesApi.Update(accountId, envelopeId, new Envelope
{
    Status = "sent"
});

示例会更新该文档中所有同名的 prefill Text tabs。如果同名字段代表不同业务数据,应增加筛选条件,或使用唯一的字段标签。相关方法及参数可查阅 C# EnvelopesApi 文档。

如果草稿中没有目标 prefill tab,也就没有可更新的 TabId。此时需要检查模板字段是否被带入;必要时,在草稿上通过 CreateDocumentTabs 创建带位置或 anchor 信息的 prefill tab,并同时设置值。不要直接用模板中的字段 ID 更新生成后的 envelope。

方案二:使用锁定的普通 recipient Text tab

如果公司名称完全由程序提供,可以在模板中使用普通 Text tab,并将其分配给正确的 signer 角色。之后在同一 composite template 的 inline template 中设置:

signer.Tabs = new Tabs
{
    TextTabs = new System.Collections.Generic.List<Text>
    {
        new Text
        {
            TabLabel = "LegalCompanyName",
            Value = "Test Customer LLC",
            Locked = "true"
        }
    }
};

使用这条路径前,必须先修改模板中的字段归属。仅在现有代码中增加 Locked,不会将原来的 sender prefill tab 转换为 recipient tab。

需要核对以下配置:

  • signer.RoleName 与 server template 中的目标角色一致。
  • inline template 中的 signer 与模板角色正确合并。
  • 模板字段确实属于该角色,且 TabLabel 一致。
  • 覆盖字段值的 inline template 在模板应用顺序中位于 server template 之后。例如 server template 使用 Sequence = "1",inline template 使用 Sequence = "2"。

DocuSign 的 composite templates 官方示例展示了按 tabLabel 设置普通文本字段值并锁定的做法。

anchor-based tabs 是否需要特殊赋值?

anchor 决定字段放在哪里,字段归属决定通过哪个接口赋值。

对于已经生成的 prefill tab,先找到它的 TabId,再更新 Value,通常不需要重新提交 AnchorString。对于普通 recipient Text tab,官方 composite templates 示例支持通过匹配 TabLabel 提供值。

原问题尚未提供完整请求和 tabs 查询响应,不能仅凭现有片段确认模板中的实际字段类型。应先查看目标字段出现在文档的 prefillTabs.textTabs 中,还是某个 recipient 的 textTabs 中,再选择对应路径。PDF annotations 的转换过程也应保留正确的字段归属;字段已经显示在文档上,并不能说明赋值请求命中了它。

备注:内容仅供参考。