跳转到内容

模板、角色与字段

模板是可重复使用的合同。它有一个名称、一份草稿以及任意数量的已发布版本。信封总是基于已发布的版本创建,而已发布的版本不可更改:编辑模板意味着保存一份新草稿,再将其发布为下一个版本。已发送的信封会保留其锁定的版本。

GET /v1/templates/tpl_…
{
"id": "tpl_3kQ9xV2mLp",
"organization": "org_…",
"name": "Mutual NDA",
"description": "Two-party NDA, US law",
"latestVersion": 3,
"draftVersion": 4,
"createdAt": "2026-10-01T09:12:44.120Z",
"updatedAt": "2026-10-12T16:03:10.981Z"
}

ID 是带前缀的字符串(tpl_、tplv_、tfl_、env_、rcp_、ses_、lnk_、evt_、whk_、whd_ 等);时间戳均为 UTC 时区的 RFC 3339 格式。

叠加模式(source: "pdf")从上传的文档开始。字段是放置在文档页面上的矩形,以 PDF 点(1/72 英寸)为单位,原点位于页面左上角,页码索引从 0 开始。上传的 .docx 文件会被转换为 PDF 一次(使用 LibreOffice,保留 Word 版式;文件中未嵌入的字体可能会被替换),此后它就和其他 PDF 一样:该文件会报告 convertedFrom: "docx"。叠加模式的版本还可以包含内容编辑(原位编辑文本、涂白、文本框、图片、页面操作),这些编辑会在版本发布时应用。

文档模式(source: "document")以富文本(ProseMirror JSON)形式存储合同本身,其中可包含 {{client.name}} 这样的变量标签、行内字段块、条件段落(仅当 showIf 表达式为真时保留)以及重复段落和表格行(数组变量中的每一项对应一个)。每个信封都会渲染出自己的 PDF,字段位置从该渲染结果中读取。在控制台中,文档模式即“从空白文档开始”。通过 API,还可以使用 POST /v1/templates/{id}/import 将 Word 文件导入为文档模式:其中的 {{tags}} 会变为变量或字段,签名行(“Signature: ____”“By: ____”“Date: ____”)会变为字段块。

新建模板提供两种起点:

  • 上传文档:一个拖放区,支持最大 25 MB 的 .pdf 和 .docx 文件。Word 文件会被转换为 PDF 并在设计器中打开,同时提醒您在放置字段之前检查转换后的版式。小的修改可以直接在 PDF 上原位完成(“编辑内容”);如需大幅改写,请修改 Word 文件后重新上传。
  • 从空白文档开始:在文档模式下撰写合同。

设计器的编辑内容模式可以更改签署人看到的内容,而不改动上传的文件。其默认工具编辑文本会突出显示页面上的文本块(根据 PDF 文本层分组而成的行和段落);点击某个文本块,或用 Tab 键移到该块后按 Enter 键,即可在原位置以相同的大小、颜色、对齐方式和字体对其进行编辑。Ctrl/Cmd+Enter 保存,Esc 取消,每项编辑都可以从编辑列表中还原。编辑与其他任何更改一样可以撤销。其他工具可用于添加涂白、文本框和图片,以及插入、删除、重新排序或旋转页面。

原位文本编辑会存储为共享同一 group 的两项:一项是覆盖原文本块的涂白(使用页面的背景色),另一项是在该块中排版的文本,沿用该块的行高和首行基线:

edits.items (excerpt)
[
{ "id": "whiteout_k2", "kind": "whiteout", "group": "blk_k1", "page": 0, "color": "#FFFFFF",
"rect": { "x": 71, "y": 209.9, "width": 452, "height": 26.9 } },
{ "id": "text_k3", "kind": "text", "group": "blk_k1", "page": 0, "rect": { "x": 72, "y": 210.9, "width": 451, "height": 24.9 },
"text": "1. Purpose. The Parties wish to evaluate a joint venture…", "original": "1. Purpose. The Parties wish to evaluate a possible business relationship…",
"size": 10.5, "lineHeight": 15.23, "baseline": 7.54, "padding": 0, "align": "left", "color": "#0B0F1A",
"face": { "source": "pdf", "name": "ABCDEF+Calibri", "fallback": "carlito" }, "font": "helvetica" }
]

face 用于选择字体:如果 PDF 的嵌入字体能绘制新文本中的每个字符,就使用该字体;否则使用内置的度量兼容字体(sans 为 Arimo,对应 Helvetica/Arial;serif 为 Tinos,对应 Times;mono 为 Cousine,对应 Courier;carlito 为 Carlito,对应 Calibri),并匹配相应的字重和样式。文本在块内自动换行;当所需行数多于原文时,编辑区域会向其下方的空白处扩展,如果没有空白,设计器会拒绝保存(“文本放不下——请缩短文本或留出空间”)。设计器和 API 共用同一套排版和字体代码,因此发布的 PDF 与预览逐行一致。

编辑只能修改草稿。发布时,编辑会应用到一份新的基础 PDF 上,其 SHA-256 即为该版本的 documentHash(签署人所见内容的哈希);上传的原始文件会作为该版本的 sourceFile 保留,下一份草稿将从该文件开始并带有相同的编辑。涂白只是在视觉上遮盖内容;原始文本仍保留在文件中的下层,因此它不是安全的涂黑处理。

角色是合同的各方。信封的收件人通过 key 与角色匹配。

{ "key": "client", "label": "Client", "kind": "signer", "order": 1, "verification": "none" }
属性 含义
key 小写标识符(^[a-z][a-z0-9_]*$),供字段和信封收件人使用
kind signer(必须有签名或姓名首字母字段)、approver、form_filler 或 cc(只接收,从不签署)
order 从 1 开始的流转顺序。顺序相同的角色并行签署;它们完成后,下一个顺序开始
verification 该角色的收件人如何证明身份:none(默认:仅凭唯一的签署链接)或 email_otp(链接加上通过电子邮件发送的验证码)。收件人可以覆盖此设置;请参阅签署人验证

passkey、id_check 和 sms_otp 出现在架构中,但尚不能用于签署:使用 passkey 或 id_check 的模板无法发布,短信验证码目前也还不会发送。

{
"id": "client_signature",
"type": "signature",
"role": "client",
"label": "Signature",
"required": true,
"rect": { "page": 1, "x": 72, "y": 610, "width": 220, "height": 48 }
}

字段类型:signature、initials、name、email、date_signed、text、number、date、checkbox、radio、dropdown、attachment、formula、stamp 以及 variable_text(由发件人通过变量填写,而不是由签署人填写)。字段还可以有:

  • variable:指向变量的 JSON Pointer(/client/name),用于绑定或预填该字段;
  • options:用于 radio 和 dropdown;
  • validation:pattern、min、max、maxLength 或 format(email、phone、date、number、currency);
  • showIf:基于变量和其他字段的条件,例如 plan != "free";
  • formula:计算得出的只读值;
  • overflow:值放不进字段框时的处理方式:shrink(默认)、wrap 或 reject。

版本的 variables 是一个 JSON Schema(draft 2020-12),描述您随每个信封发送的数据;版本的 sampleVariables 是一个示例。POST /v1/envelopes 会依据它校验您的 variables,并用 JSON Pointer 报告每个问题:

{
"type": "https://bonafidesign.com/problems/validation-error",
"title": "Validation failed",
"status": 422,
"detail": "The request is invalid.",
"errors": [
{ "pointer": "/variables/client/name", "message": "is required", "hint": "Provide a value for 'name'." }
]
}

如需在发送前查看结果,可以使用 POST /v1/templates/{id}/versions/{version}/render({ "variables": { … } } → PDF)渲染任意版本的带水印预览,或使用 ?dry_run=true 创建信封。

大多数团队会在控制台的设计器中设计模板。设计器能做的一切,API 都能做到:

  1. POST /v1/templates,请求体为 { "name": "Mutual NDA" }。
  2. POST /v1/templates/{id}/files,将 PDF(或 .docx)作为请求体(Content-Type: application/pdf)或作为 multipart 字段 file 上传。最大 25 MB。响应中包含文件 ID(tfl_…)、页数和页面尺寸。
  3. PUT /v1/templates/{id}/draft,附带 roles、fields、variables(以及 file,或 source: "document" 加 content)。草稿按原样保存;此时不做任何检查。
  4. POST /v1/templates/{id}/publish。发布时会对草稿进行 lint 检查:每个字段的角色都存在、每个签署人角色都有签名字段、字段位于页面范围内、单选和下拉字段都有选项、表达式可以解析。问题会以 422 返回,并附带 /fields/3/rect 这样的指针。
Terminal window
curl https://api.bonafidesign.com/v1/templates/tpl_3kQ9xV2mLp/files \
-H "Authorization: Bearer $BONA_FIDE_API_KEY" \
-H "Content-Type: application/pdf" \
--data-binary @nda.pdf

版本端点接受数字、latest 或 draft:GET /v1/templates/{id}/versions/latest、GET /v1/templates/{id}/versions/2/document(基础 PDF)。从未被信封或签署链接使用过的模板可以删除;否则 DELETE 会返回 409 in-use。