Docuseal 3.3.4 API 使用详解

Docuseal 3.3.4 REST API 实测使用详解:X-Auth-Token 认证与首次调用、模板/提交/签署人/事件/工具五大域端点逐一 curl 实测回显,分页与过滤约定、错误码排查、PDF 合并与验签实战。

DocusealREST API自托管2026/10/30

Docuseal 3.3.4 API 使用详解

目标:把 Docuseal 3.3.4 自托管版对外提供的 REST API 完整过一遍——认证方式、五大端点域、分页与过滤约定、错误码行为,全部在真实实例上用 curl 逐条发起请求并记录原始回显,最终以 API 驱动完成「发起签署 → 回填字段 → 生成已签署 PDF → 数字验签」的端到端链路。已在 Ubuntu 22.04(实例部署方式见《Docuseal 3.3.4 Docker Compose 部署指南》)实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04(x86_64)
  • Docuseal:3.3.4(自托管开源版,Ruby 4.0.9 + Puma 8.0.2)
  • 实例入口:http://127.0.0.1:8132(实例「设置 → App URL」配置为 http://localhost:8132,回显中的文件链接域名以该设置为准)
  • 管理员账号:admin@docuseal.local(密码 q1w2e3r4,初始化过程见《Docuseal 3.3.4 Docker Compose 部署指南》)
  • 客户端工具:curl 8.18.0(curl --version 实查)
  • 数据库:PostgreSQL 16
  • 实测日期:2026-10-30
  • 路由证据:实例内 bin/rails routes 输出(260 行,其中 /api、/api/tools 相关 27 条,完整清单见三、API 总览)

二、前置条件

2.1 获取 API Token

Docuseal 的 API 调用使用 API Token 鉴权,获取路径在 Web 界面内:

  1. 以 admin@docuseal.local / q1w2e3r4 登录实例;
  2. 进入右上角 Settings → API 页面;
  3. 点击 Create API Key,系统要求再次输入登录密码做二次确认(防止他人在已登录的浏览器上偷偷取走密钥);
  4. 确认后界面显示一串 40 位随机字符串,即 API Token,仅此一次完整展示,应立即复制保存。

按敏感信息占位约定,本文后续统一以环境变量注入 Token,不在正文落明文:

# 将界面上取到的 40 位 API Token 导出为环境变量,后续所有 curl 命令引用它
export DOCUSEAL_API_TOKEN='替换为你的40位API_Token'

2.2 客户端与连通性检查

# 确认实例可达:未带认证头访问列表接口应返回 401 JSON,而不是连接错误
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8132/api/templates
# 实测输出:401

返回 401 说明服务与 API 路由均正常,只差认证头,可以进入下一节。

三、API 总览

3.1 协议与版本约定

  • 协议形态:HTTP + JSON 的 REST 风格接口,请求与响应主体均为 JSON(文件类参数用 base64 编码塞进 JSON);
  • 路径前缀:自托管开源版所有 API 以 /api 开头,没有 /api/v1 这样的版本子前缀(bin/rails routes 实查:27 条 API 路由全部直接挂在 /api 下);DocuSeal 云端版(api.docuseal.com)的官方文档示例则使用独立 API 域名,两者端点集合并不相同;
  • 端点差异:开源版不提供「创建模板」「HTML 转签署表单」等云端专属端点——POST /api/templates 实测直接返回 404(见 5.2.6);模板只能走界面创建,或通过 clone 端点复制既有模板;
  • 鉴权方式:仅支持请求头 X-Auth-Token: <API Token>,不支持 Authorization: Bearer(实测见 4.2);
  • 限流约定:应用依赖清单中未见任何限流组件(Gemfile 中无 rack-attack/throttle 相关条目,实查于 2026-10-30),自托管版未内置速率限制,公网暴露时需在反向代理层自行加防护;
  • 幂等与软删除:DELETE 类端点默认是归档(写 archived_at 字段),提交类端点追加 permanently=true 参数才是永久删除。

3.2 端点域与路由总表

实测路由总表(按域归并,来自 bin/rails routes):

端点域方法与路径用途
账户GET /api/user查看当前 Token 对应的账号身份
模板GET /api/templates模板列表(分页+过滤)
模板GET / PATCH / PUT / DELETE /api/templates/{id}模板详情 / 更新(含字段、角色、归档)/ 归档删除
模板POST /api/templates/{template_id}/clone克隆模板
模板GET / POST /api/templates/{template_id}/submissions某模板下的提交列表 / 发起签署
提交POST /api/submissions/init创建不发送邮件通知的提交(预创建)
提交POST /api/submissions/emails创建提交并携带邮件正文发送
提交GET / POST /api/submissions提交列表(分页+过滤)/ 创建提交
提交GET / PATCH / PUT / DELETE /api/submissions/{id}提交详情 / 改名与过期时间 / 归档或永久删除
提交GET /api/submissions/{submission_id}/documents获取已签署文档与审计日志的下载地址
签署人GET /api/submitters签署人列表(分页+过滤)
签署人GET / PATCH / PUT /api/submitters/{id}签署人详情 / 回填字段值并标记完成
表单视图POST /api/submitter_form_views上报「签署人已打开表单」(打点)
事件GET /api/events/form/{type}按类型拉取表单侧事件(viewed/completed 等)
事件GET /api/events/submission/{type}按类型拉取提交侧事件(created/completed 等)
工具POST /api/tools/merge合并多个 PDF 为一个
工具POST /api/tools/verify校验 PDF 内数字签名的有效性

3.3 通用响应结构

  • 单对象端点直接返回对象 JSON;列表端点固定返回 {"data": [...], "pagination": {...}} 双键结构(见六、分页与过滤);
  • 资源对外同时有 id(整数)与 slug(公开短串)两种标识:API 内部引用多用 id,而面向被签署人的分享/嵌入链接全部用 slug;
  • 时间字段一律 ISO 8601 UTC 格式(如 2026-10-30T12:03:09.843Z)。

四、认证与首次调用

4.1 首次调用:查看账号身份

# 用 API Token 调用最简单的账户端点,验证 Token 有效
curl -s -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" http://127.0.0.1:8132/api/user

实测回显:

{"id":1,"first_name":"Admin","last_name":"Docuseal","email":"admin@docuseal.local"}

4.2 认证失败的三种实测形态

认证相关的失败形态固定返回 HTTP 401 与 {"error":"Not authenticated"},以下三种情况实测回显完全一致:

# 情形一:不带认证头
curl -s -w '\nHTTP:%{http_code}\n' http://127.0.0.1:8132/api/templates
# 实测输出:{"error":"Not authenticated"} / HTTP:401

# 情形二:Token 值错误
curl -s -w '\nHTTP:%{http_code}\n' -H 'X-Auth-Token: WRONG_TOKEN_123' http://127.0.0.1:8132/api/templates
# 实测输出:{"error":"Not authenticated"} / HTTP:401

# 情形三:误用 Authorization: Bearer(不支持)
curl -s -w '\nHTTP:%{http_code}\n' -H "Authorization: Bearer $DOCUSEAL_API_TOKEN" http://127.0.0.1:8132/api/templates
# 实测输出:{"error":"Not authenticated"} / HTTP:401

排查口诀:先确认请求头名字是 X-Auth-Token 而不是 Authorization,再确认 Token 值是从「设置 → API」完整复制的 40 位字符串(界面只显示一次,丢了只能新建)。

五、各 API 域详解

5.1 模板域(/api/templates)

5.1.1 模板列表:GET /api/templates

curl -s -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" http://127.0.0.1:8132/api/templates

实测回显(节选,fields 中每个字段带 areas 坐标数组):

{"data":[{"id":2,"name":"Service Agreement Template","slug":"mgM7Xu5MVrjsEv",
  "schema":[{"attachment_uuid":"81987210-eb82-412b-8b21-0c8da17ad07e","name":"test-contract"}],
  "submitters":[{"name":"First Party","uuid":"26b45529-f40d-442a-9260-045181533520"}],
  "fields":[
    {"name":"Full Name","type":"text","required":true,
     "areas":[{"x":72,"y":700,"w":200,"h":30,"attachment_uuid":"81987210-eb82-412b-8b21-0c8da17ad07e","page":1}]},
    {"name":"Signature","type":"signature","required":true,
     "areas":[{"x":72,"y":640,"w":200,"h":44,"attachment_uuid":"81987210-eb82-412b-8b21-0c8da17ad07e","page":1}]},
    {"name":"Contract Date","type":"date",
     "areas":[{"x":350,"y":700,"w":160,"h":30,"attachment_uuid":"81987210-eb82-412b-8b21-0c8da17ad07e","page":1}]}],
  "variables_schema":{},"preferences":{},"source":"native",
  "created_at":"2026-10-30T12:00:32.414Z","updated_at":"2026-10-30T12:02:31.257Z",
  "archived_at":null,"author_id":1,"folder_name":"Default",
  "author":{"id":1,"email":"admin@docuseal.local","first_name":"Admin","last_name":"Docuseal"},
  "documents":[{"id":3,"uuid":"81987210-eb82-412b-8b21-0c8da17ad07e","url":"http://localhost:8132/file/…/test-contract.pdf","preview_image_url":"http://localhost:8132/file/…"}]},
  …],
 "pagination":{"count":1,"next":2,"prev":2}}

要点:fields[].areas[].x/y/w/h 是字段在文档页上的坐标(单位为 PDF 点),page 从 1 起;schema[].attachment_uuid 把字段坐标关联到具体文档附件;documents[].url 是带签名的临时下载地址。

5.1.2 模板详情:GET /api/templates/{id}

curl -s -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" http://127.0.0.1:8132/api/templates/2

实测回显结构与 5.1.1 的单元素一致(data 数组元素即模板详情对象),不再重复。

5.1.3 更新模板:PATCH /api/templates/{id}

支持整体替换 fields、调整角色 roles、移动目录 folder_name、归档 archived 等参数:

# 幂等改名:名称不变时仅返回 id 与原 updated_at
curl -s -X PATCH -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" -H 'Content-Type: application/json' \
  -d '{"name":"Service Agreement Template"}' \
  http://127.0.0.1:8132/api/templates/2

实测回显:

{"id":2,"updated_at":"2026-10-30T12:02:31.257Z"}

模板字段(fields)与签署人角色(submitters/roles)在部署实例上的图形化编辑方式见《Docuseal 3.3.4 配置参数详解》中对实例设置体系的说明;本端点适合做字段的程序化批量调整。

5.1.4 克隆模板:POST /api/templates/{template_id}/clone

curl -s -X POST -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" -H 'Content-Type: application/json' \
  -d '{"name":"Cloned Service Agreement"}' \
  http://127.0.0.1:8132/api/templates/2/clone

实测回显(节选,返回完整新模板对象,含与源模板相同坐标的 fields):

{"id":4,"name":"Cloned Service Agreement","slug":"QGJeVZGeEsTLnh",
 "schema":[{"attachment_uuid":"99daa972-c8eb-4b03-ba64-b15a721b61b7","name":"test-contract"}],
 "submitters":[{"name":"First Party","uuid":"2f6befc7-42dd-4a97-b0e3-eaea5f49df69"}],
 "fields":[{"name":"Full Name","type":"text","required":true,
   "areas":[{"x":72,"y":700,"w":200,"h":30,"attachment_uuid":"99daa972-c8eb-4b03-ba64-b15a721b61b7","page":1}],
   "uuid":"08633619-edd7-482e-8a90-d60c8544cd85","submitter_uuid":null},
   …]}

5.1.5 归档模板:DELETE /api/templates/{id}

# 清理克隆出的实验模板(id=4)
curl -s -X DELETE -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" http://127.0.0.1:8132/api/templates/4

实测回显:

{"id":4,"archived_at":"2026-10-30T12:26:12.271Z"}

注意回显:DELETE 返回的是归档时间而非成功标记——模板删除是软删除,归档后从默认列表消失,可用 GET /api/templates?archived=true 找回。

5.1.6 开源版没有「创建模板」端点(实测)

curl -s -w '\nHTTP:%{http_code}\n' -X POST -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" \
  -H 'Content-Type: application/json' -d '{"name":"x"}' http://127.0.0.1:8132/api/templates

实测回显:

{"status":404}
HTTP:404

路由表中 /api/templates/:id 只注册了 GET/PATCH/PUT/DELETE 四个动词,没有 POST。需要程序化建模板时,用 5.1.4 的 clone 端点复制一份再改字段。

5.2 提交域(/api/submissions)

「提交(Submission)」是模板的一次具体签署实例:模板是「空白合同」,提交是「发给张三的那份合同」。

5.2.1 发起签署:POST /api/templates/{template_id}/submissions

curl -s -X POST -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" -H 'Content-Type: application/json' \
  -d '{"submitters":[{"name":"Li Si","email":"lisi@example.com","role":"First Party","send_email":false}]}' \
  http://127.0.0.1:8132/api/templates/2/submissions

实测回显(返回的是签署人数组,不是提交对象):

[{"id":4,"slug":"Jx8zrhpyr2rKf5","uuid":"26b45529-f40d-442a-9260-045181533520",
  "name":"Li Si","email":"lisi@example.com","phone":null,
  "completed_at":null,"declined_at":null,"external_id":null,"submission_id":4,
  "metadata":{},"opened_at":null,"sent_at":null,
  "created_at":"2026-10-30T12:26:10.738Z","updated_at":"2026-10-30T12:26:10.738Z",
  "status":"awaiting","application_key":null,"values":[],
  "preferences":{"send_email":false,"send_sms":false},"role":"First Party",
  "embed_src":"http://localhost:8132/s/Jx8zrhpyr2rKf5"}]

参数要点:

参数位置说明
submittersbody 必填签署人数组,缺省直接 422(见 5.2.6)
submitters[].name/email/phonebody签署人身份信息,email 用于站内发送与通知
submitters[].rolebody必须匹配模板中定义的角色名(本模板为 First Party)
submitters[].send_emailbody是否发邮件通知;省略时默认 true(源码 submissions_controller.rb:params[:send_email] = true unless params.key?(:send_email)),未配置 SMTP 的实例务必显式传 false
submitters[].valuesbody可在发起时直接预填字段值
submitters[].completedbody传 true 可直接代替签署人完成(测试/批量场景)

两个常用链接:embed_src(/s/{slug})是该签署人的填写表单地址,可直接嵌入业务系统的 iframe;提交本身还有 /e/{slug} 概览页地址(见 5.2.5 回显中的 submission_url)。

5.2.2 预创建提交:POST /api/submissions/init

与 5.2.1 的区别:不要求 email、不发送任何通知,适合「先建单、后补联系方式」的流程编排:

curl -s -X POST -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" -H 'Content-Type: application/json' \
  -d '{"template_id":2,"submitters":[{"name":"Wang Wu","role":"First Party","send_email":false}]}' \
  http://127.0.0.1:8132/api/submissions/init

实测回显(节选):

{"id":3,"submitters":[{"id":3,"slug":"Px8Wat3SmQ54MA","uuid":"26b45529-f40d-442a-9260-045181533520",
  "name":"Wang Wu","email":null,"phone":null,"completed_at":null,"submission_id":3,
  "status":"awaiting","role":"First Party","embed_src":"http://localhost:8132/s/Px8Wat3SmQ54MA"}],
 "expire_at":null,"created_at":"2026-10-30T12:24:58.333Z"}

5.2.3 提交列表与详情:GET /api/submissions、GET /api/submissions/{id}

curl -s -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" http://127.0.0.1:8132/api/submissions

实测回显(节选):

{"data":[{"id":1,"name":null,"slug":"H7JMvpqxhsZuGS","source":"api","submitters_order":"preserved",
  "expire_at":null,"created_at":"2026-10-30T12:02:51.930Z","updated_at":"2026-10-30T12:03:11.033Z",
  "archived_at":null,
  "submitters":[{"id":1,"slug":"GjRRFCfzgaeuva","name":"Zhang San","email":"zhangsan@example.com",
    "completed_at":"2026-10-30T12:03:09.843Z","status":"completed","role":"First Party"}],
  "template":{"id":2,"name":"Service Agreement Template","folder_name":"Default"},
  "created_by_user":{"id":1,"email":"admin@docuseal.local","first_name":"Admin","last_name":"Docuseal"},
  …}],
 "pagination":{"count":1,"next":1,"prev":1}}

单提交详情 GET /api/submissions/1 返回同一结构外加 submission_events 事件明细数组,此处不再重复。

5.2.4 更新与删除提交:PATCH / DELETE /api/submissions/{id}

# 重命名提交
curl -s -X PATCH -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" -H 'Content-Type: application/json' \
  -d '{"name":"Li Si Service Agreement"}' \
  http://127.0.0.1:8132/api/submissions/4

实测回显(节选,name 已生效):

{"id":4,"name":"Li Si Service Agreement","slug":"1UfXHdM2q3UTJY","source":"api",
 "updated_at":"2026-10-30T12:26:12.194Z",
 "submitters":[{"id":4,"slug":"Jx8zrhpyr2rKf5","name":"Li Si","status":"completed",…}]}
# 永久删除(不带 permanently 则只是归档)
curl -s -X DELETE -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" -H 'Content-Type: application/json' \
  -d '{"permanently":true}' \
  http://127.0.0.1:8132/api/submissions/4

实测回显:

{"id":4,"archived_at":null}

可更新字段白名单为 name、expire_at、archived、archived_at(源码 submissions_controller.rb 的 submission_params),其余字段改动会被静默忽略。

5.2.5 下载已签署文档:GET /api/submissions/{submission_id}/documents

签署完成后(完成动作见 5.3.2),通过该端点取回生成好的 PDF 与审计日志:

curl -s -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" http://127.0.0.1:8132/api/submissions/1/documents

实测回显:

{"id":1,"documents":[{"name":"test-contract","url":"http://localhost:8132/file/WyIyNzQ4ZWI5OS00MmM0LTQxNGItOTcwOC01ZWIzN2JlNTcxOTUiLCJibG9iIiwxNzkzMzY1MzkzXQ--bf2c7a1e6c77d8fc39c17b13385709247ad40067dd879516f862208e40119caa/test-contract.pdf"}]}

下载地址是带签名的临时 URL(含过期时间戳),直接 curl -o 即可取回文件;对提交 1 下载得到的已签署文档实测 9832 字节,含签署值与 DocuSeal 数字签名(验签见 5.4.2)。审计日志(Audit Log PDF,53533 字节)会随事件域回显中的 audit_log_url 一并给出。

5.2.6 参数缺失与资源不存在的错误形态(实测)

# 缺 submitters:HTTP 422 + 明确错误字段名
curl -s -w '\nHTTP:%{http_code}\n' -X POST -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" \
  -H 'Content-Type: application/json' -d '{}' \
  http://127.0.0.1:8132/api/templates/2/submissions
# 实测输出:{"error":"submitters is required"} / HTTP:422

# 资源不存在:HTTP 404
curl -s -w '\nHTTP:%{http_code}\n' -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" \
  http://127.0.0.1:8132/api/templates/9999
# 实测输出:{"status":404} / HTTP:404

5.3 签署人域(/api/submitters)

5.3.1 列表与详情:GET /api/submitters、GET /api/submitters/{id}

curl -s -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" http://127.0.0.1:8132/api/submitters/1

实测回显:

{"id":1,"slug":"GjRRFCfzgaeuva","uuid":"26b45529-f40d-442a-9260-045181533520",
 "name":"Zhang San","email":"zhangsan@example.com","phone":null,
 "completed_at":"2026-10-30T12:03:09.843Z","declined_at":null,
 "external_id":null,"submission_id":1,"metadata":{},"opened_at":null,"sent_at":null,
 "created_at":"2026-10-30T12:02:51.955Z","updated_at":"2026-10-30T12:03:09.847Z",
 "status":"completed","application_key":null,
 "template":{"id":2,"name":"Service Agreement Template",
  "created_at":"2026-10-30T12:00:32.414Z","updated_at":"2026-10-30T12:02:31.257Z"},
 "values":[],
 "documents":[{"name":"test-contract","url":"http://localhost:8132/file/…/test-contract.pdf"}],
 "preferences":{"send_email":false,"send_sms":false},
 "submission_events":[{"id":1,"submitter_id":1,"event_type":"api_complete_form",
  "event_timestamp":"2026-10-30T12:03:09.908Z","data":{}}],
 "role":"First Party"}

签署人列表 GET /api/submitters 返回 data + pagination 结构,元素与上述对象一致,并支持 submission_id、template_id、external_id、slug、完成时间区间等过滤(见六、表 6-2)。

5.3.2 代填字段并完成签署:PATCH /api/submitters/{id}

这是以 API 驱动整条签署链的核心端点:回填字段值后标记 completed,实例即生成已签署 PDF 与审计日志:

curl -s -X PATCH -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" -H 'Content-Type: application/json' \
  -d '{"name":"Li Si","values":{"Full Name":"Li Si","Contract Date":"2026-10-30"},"completed":true}' \
  http://127.0.0.1:8132/api/submitters/4

实测回显(节选):

{"id":4,"slug":"Jx8zrhpyr2rKf5","name":"Li Si","email":"lisi@example.com",
 "completed_at":"2026-10-30T12:26:10.975Z","status":"completed",
 "opened_at":"2026-10-30T12:26:10.835Z",
 "role":"First Party","embed_src":"http://localhost:8132/s/Jx8zrhpyr2rKf5",…}

参数要点:

  • values 是「字段名 → 值」的字典,字段名必须与模板 fields[].name 完全一致(含大小写与空格),否则该值被静默丢弃;
  • completed: true 触发文档合成;完成后再次 PATCH 同一签署人会被拒绝(源码校验:已完成的签署人返回 422 Submitter has already completed the submission.);
  • 其他可用参数:declined(拒签)、metadata(自由 JSON,用于业务侧回传关联 ID)、fields 数组(可细粒度指定每个字段)。

5.4 工具域(/api/tools)

5.4.1 合并 PDF:POST /api/tools/merge

请求体为 JSON:files 数组放多个 base64 编码的 PDF(本例为提交 1 生成的已签署合同 9832B 与其审计日志 53533B):

# 用 python 生成请求体并调用(base64 来自上一步下载的两份 PDF)
python3 - <<'EOF'
import base64, json
def b64(p):
    return base64.b64encode(open(p,'rb').read()).decode()
body = {"files": [b64('signed-contract.pdf'), b64('audit-log.pdf')]}
open('merge_req.json','w').write(json.dumps(body))
EOF
curl -s -X POST -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" -H 'Content-Type: application/json' \
  --data-binary @merge_req.json http://127.0.0.1:8132/api/tools/merge > merge_resp.json
# 从响应中解码出合并结果
python3 -c "import json,base64;d=json.load(open('merge_resp.json'));open('merged.pdf','wb').write(base64.b64decode(d['data']))"
ls -l merged.pdf

实测结果:响应为 {"data":"JVBERi0xLjcNCi…"}(base64,内含换行符,解码库会自动忽略),解码落盘得到 merged.pdf 共 54543 字节,可正常打开,页数为两份输入之和。

5.4.2 验证数字签名:POST /api/tools/verify

请求体为 JSON:file 放一个 base64 编码的 PDF(本例为已签署合同):

python3 -c "import base64,json;open('verify_req.json','w').write(json.dumps({'file':base64.b64encode(open('signed-contract.pdf','rb').read()).decode()}))"
curl -s -X POST -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" -H 'Content-Type: application/json' \
  --data-binary @verify_req.json http://127.0.0.1:8132/api/tools/verify

实测回显(完整):

{"checksum_status":"verified",
 "signatures":[{"verification_result":[
    {"type":"success","content":"Signature valid"},
    {"type":"success","content":"Signed with trusted certificate"},
    {"type":"info","content":"Certificate chain: DocuSeal -> DocuSeal Sub-CA -> DocuSeal Root CA"}],
  "signer_name":"DocuSeal","signing_reason":"Signed with DocuSeal.com",
  "signing_time":"2026-10-30T12:03:10.000Z","signature_type":"adbe.pkcs7.detached"}]}

要点:checksum_status: verified 表示文档内容自签署后未被篡改;实例使用自建证书链(DocuSeal 根证书 → 子 CA → 文档签名),签名格式为 Adobe 通用 的 adbe.pkcs7.detached,Adobe Reader 等主流阅读器可显示签名面板。

5.5 表单视图与事件域

5.5.1 上报表单打开事件:POST /api/submitter_form_views

curl -s -X POST -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" -H 'Content-Type: application/json' \
  -d '{"submitter_slug":"Jx8zrhpyr2rKf5"}' \
  http://127.0.0.1:8132/api/submitter_form_views

实测回显:

{}

响应体恒为空对象;副作用才是重点:源码(submitter_form_views_controller.rb)显示该调用会把签署人的 opened_at 置为当前时间、追加 form.viewed 跟踪事件——适合把自有系统的「用户已打开填写页」动作同步进 Docuseal 的审计事件流。

5.5.2 拉取事件:GET /api/events/submission/{type}、GET /api/events/form/{type}

curl -s -H "X-Auth-Token: $DOCUSEAL_API_TOKEN" http://127.0.0.1:8132/api/events/submission/completed

实测回显(节选,data 数组每项是一个事件快照):

{"data":[{"event_type":"submission.completed","timestamp":"2026-10-30T12:03:09.843Z",
  "data":{"id":1,"slug":"H7JMvpqxhsZuGS","source":"api","submitters_order":"preserved",
   "submitters":[{"id":1,"slug":"GjRRFCfzgaeuva","name":"Zhang San","status":"completed",
     "documents":[{"name":"test-contract","url":"http://localhost:8132/file/…/test-contract.pdf"}],
     "role":"First Party"}],
   "template":{"id":2,"name":"Service Agreement Template","folder_name":"Default"},
   "created_by_user":{"id":1,"email":"admin@docuseal.local",…},…}},…]}

表单侧事件 GET /api/events/form/completed 返回 event_type: form.completed,载荷额外带 audit_log_url、submission_url(/e/{slug} 概览页)与签署值明细。事件类型与 URL 中的 {type} 对应(completed、viewed、created 等),自托管版以拉取方式消费事件;云端版的 Webhook 推送在开源版中不存在。

六、分页、过滤与通用约定

6.1 分页结构(实测)

所有列表端点固定返回双键结构,pagination 采用游标式(以资源 id 为游标),而非页码式:

"pagination": {"count": 1, "next": 2, "prev": 2}
  • count:本页条数;next/prev:下一页/上一页的起始资源 id(本页只有一条时两者相同);
  • 翻页参数为 per_page 与 page(page 语义配合 next 游标使用),如 GET /api/submissions?per_page=1&page=1 实测返回单条记录与对应 pagination。

6.2 过滤参数(源码实查,2026-10-30)

端点支持的查询参数
GET /api/templatesq(关键词)、archived、application_key、external_id、slug、shared
GET /api/submissionsq、slug、template_folder(按模板目录全名)、archived,及通用过滤(模板 id、创建时间区间等)
GET /api/submittersapplication_key、external_id、slug、submission_id、template_id、完成时间区间

6.3 其他通用约定

  • 链接域名:回显中的文件/表单链接域名取自实例「设置 → App URL」(本实例配置为 http://localhost:8132),与 curl 请求所用的 127.0.0.1 不同属正常现象;生产环境应把 App URL 设为对外域名,否则生成的签署链接不可访问;
  • 临时下载地址:/file/{签名}/{文件名} 形态的 URL 带过期时间戳,取到后应及时下载,不能长期外发;
  • 错误码速查:401 认证失败(见 4.2)、404 资源不存在或动词未注册(见 5.1.6)、422 参数校验失败(错误说明在 error 字段,如 submitters is required)。

七、常见问题

Q1:请求一直返回 {"error":"Not authenticated"} 怎么排查? 按顺序核对三点:请求头名必须是 X-Auth-Token(Authorization: Bearer 不被识别,实测 401);Token 值是否完整复制(40 位,界面只展示一次);Token 是否与目标实例匹配(多套实例的 Token 不通用)。

Q2:明明资源存在,请求却 404? 优先检查 HTTP 动词。典型陷阱:curl 的 -d 参数默认发送 POST,若目标是 PATCH/DELETE 端点而不加 -X PATCH/-X DELETE,实际请求的是未注册的 POST /api/xxx/{id},返回 404。本文所有变更类示例均显式写了 -X 动词,即源于此实测教训。

Q3:POST /api/templates/2/submissions 返回 422 submitters is required? 请求体缺 submitters 数组。注意数组内每项的 role 必须与模板角色名逐字一致;未配置 SMTP 时务必传 send_email: false,否则省略时默认 true,提交会进入邮件发送队列并等待重试。

Q4:签署人完成后再调 PATCH 报 422? 签署完成后提交整体锁定,再次更新同一签署人返回 Submitter has already completed the submission.。需要修订时只能创建新提交;values 预填应在发起提交(submitters[].values)或首次完成前完成。

Q5:values 里填了字段但生成的 PDF 没有值? 字段名键必须与模板 fields[].name 完全一致(含大小写与空格),不匹配的键会被静默忽略而不报错。先 GET /api/templates/{id} 核对字段名再回填。

Q6:回显里的链接为什么是 localhost 而不是我访问用的地址? 生成链接的域名取自实例设置中的 App URL,与请求 Host 无关。部署后应在「设置 → App URL」中配置真实对外地址(含端口或反代域名),否则发给签署人的 embed_src、/e/{slug} 链接在对方环境不可达。

Q7:/api/tools/merge 返回的 data 直接 base64 解码失败? 响应中的 base64 按行折叠含有换行符,Python 的 base64.b64decode 会自动忽略,部分语言的严格解码器需要先去除 \n 再解码。

八、参考链接