跳转到内容

Envelopes API

Envelopes API 让您从自己的系统发送文档签署。envelope 就是应用中所说的签署请求:同一个东西,只是 API 里的名称不同。它包含最多 10 份文档、签署或接收这些文档的人,以及每位签署人要填写的字段。

AutomaDoc Sign 记录的是带审计记录的简单电子签名:谁签署、何时、在哪里签署,以及每个文件的指纹(SHA-256)。它不是基于证书的数字签名。有些文档(遗嘱、家事事务、法院文书)和一些官方系统需要其他形式的签名,请先确认您的文档有什么要求。

每个接口都需要公司 API 密钥(以 amk_ 开头),放在以下任一请求头中:

X-Webhook-API-Key: amk_…
Authorization: Bearer amk_…

管理员在企业门户的公司 → API 密钥下创建公司密钥(请参阅 API 快速入门)。模板自己的密钥只能访问那一个模板,无法访问贵公司的签署请求:使用它会被拒绝,返回 API_KEY_INVALID。一个密钥可以看到其公司的所有签署请求,无论是通过 API 创建还是在门户中创建的,但看不到其他公司的任何内容(ENVELOPE_NOT_FOUND)。

适用两项频率限制:

  • 每个密钥每分钟 60 个请求,所有 envelope 接口合计。
  • 每家公司每分钟 600 份文档,与文档 API 和 HTTP 触发器共用。一次创建按其中的文档数计算。

超过任一限制都会返回 429 和 RATE_LIMITED。

  1. POST /api/v1/envelopes 保存您的文档并立即返回 201,此时签署请求仍是 draft,每份文档为 prepareState: "pending"。
  2. AutomaDoc 预处理每份文档:Word、Excel 和 PowerPoint 文件转换为 PDF,并在文字中查找您的锚点和 [[…]] 标签。30 分钟后仍处于 pending 的文档会以 timeout 失败。
  3. 最后一份文档就绪后,系统会放置由锚点和标签生成的字段;如果设置了 send: true,签署请求随即发出。轮到的邮件收件人会收到邀请。
  4. 读取 GET /api/v1/envelopes/:id 跟踪进度。如果无法发送,它会保持 draft,并由 sendError 说明原因。

公开 API 没有单独的发送接口:创建时未设置 send: true 的签署请求会一直是草稿。无法发送的草稿也不能通过 API 重试,请创建一个新的签署请求。30 天无人改动的草稿会被删除。

POST https://api.automadoc.cc/api/v1/envelopes

请求体可以用 JSON 发送(Content-Type: application/json,最大 14 MB),也可以用 multipart/form-data 发送:envelope 部分包含同样的 JSON,每个文件各占一个部分(整个请求最大 26 MB)。

字段 必填 作用
title 是 显示给签署人并出现在邮件中。最多 200 个字符。
message 否 给收件人的留言,最多 1,000 个字符。
documents 是 1 到 10 份文档,按顺序排列(见下文)。
recipients 是 1 到 20 位收件人(见下文)。
fields 否 按坐标放置的字段(见下文)。最多 500 个。
anchors 否 相对于文档中文字放置的字段(见下文)。最多 50 个。
autoTags 否 设为 true 时,根据文档中写的 [[…]] 标签放置字段(见下文)。
send 否 设为 true 时,文档预处理完毕、字段放置好后立即发送签署请求。否则保持草稿状态。
locale 否 邮件和签署页面的语言:en、zh、id、es、vi、th 或 ja。其他值会被忽略。
timezone 否 IANA 时区(Asia/Jakarta),用于文档和证书上写入的日期。默认 UTC。
expiryDays 否 从发送到签署请求过期的天数:1 到 120,默认 30。
reminders 否 { "everyDays": 3, "max": 3 }(默认值;everyDays 为 1 到 30,max 为 0 到 10),或 false 表示不提醒。
appendCertificate 否 默认 true:每份已签署的 PDF 末尾附有完成证书。证书也始终可以单独下载。

每份文档只能是以下其中一种:

字段 含义
base64 文件字节的 base64 编码(可以带 data: 前缀)。一个请求中所有 base64 文档解码后合计最多 10 MB;更大的文件请用 multipart 发送。
file multipart 请求中包含该文件的部分的名称。
generationId AutomaDoc 为贵公司生成的已完成文档(文档 API 的 generationId,或任何仍在保留期内的其他生成文档)。它的文件会被复制到签署请求中。

name 为选填:默认取该部分的文件名、生成文件的名称,或“Document 1”“Document 2”。末尾的 .pdf、.docx、.xlsx 或 .pptx 会被去掉。文件可以是 PDF、Word、Excel 或 PowerPoint,依据内容识别,从不依据文件名。每个文件最大 25 MB,一个签署请求的文件合计最大 50 MB。

字段 必填 作用
key 是 您给这位收件人起的名称(client),供 fields 和 anchors 引用,并在每个响应中返回。1 到 60 个字母、数字、_、- 或 .,在请求中唯一。
role 是 signer(填写字段并签署)或 cc(接收签署结果)。
name 是 最多 120 个字符。
email 使用 reach: "email" 时必填 邀请发送到的地址。链接收件人可不填。
reach 否 "email"(默认):轮到此收件人时,AutomaDoc 用邮件发送邀请。"link":不发送邮件,创建响应会返回一个 signingUrl,由您自行转交。
routingOrder 否 1 到 100,默认 1。号码相同的收件人同时签署;号码较大的收件人要等所有号码较小的人都完成后才签署。
accessCode 否 6 到 128 个字符,收件人必须输入后才能看到文档。输错五次,链接就会被锁定。请由您自己把访问码交给收件人,不要与链接放在同一条消息中。
slot 否 配合 autoTags 使用:此收件人负责填写的标签中的角色名(Client)。
字段 必填 作用
document 是 文档在 documents 中的索引,从 0 开始。
recipient 是 收件人的 key。只有签署人才有字段。
type 是 signature、initials、name、date_signed、text、checkbox、company 或 email。
page 是 页码,从 1 开始。
x, y, w, h 是 位置和大小,单位为磅(1/72 英寸),从页面显示时(经过任何旋转后)的左上角开始测量。字段的宽和高至少为 8 磅,且必须位于页面内。
required 否 默认 true。
label 否 显示给签署人的提示,最多 100 个字符。
options 否 用于文本字段:maxLength(1 到 1,000)、validate("number" 或 "email")、fontSize(6 到 72,会缩小以适应)。

name 和 email 会预先填入收件人的姓名和地址,签署人可以修改;date_signed 会填入签署日期,按签署请求的时区书写。页码和位置在签署请求发送时根据预处理后的文档检查(field_bad_page、field_off_page),因为 Word 文件在转换之前没有页面。

锚点相对于文档中已有的文字放置字段,因此不需要坐标:

字段 必填 作用
anchor 是 要查找的文字,最多 200 个字符。完全一致且区分大小写;任意一串空格或换行都能匹配任意另一串。
recipient 是 收件人的 key。
type 是 字段类型,同上。
occurrence 否 "all"(默认:每个匹配处一个字段,最多 200 个),或 n,仅第 n 个匹配,按阅读顺序在签署请求的所有文档中计算。
offsetX, offsetY 否 从匹配文字左上角到字段左上角的磅数(-2,000 到 2,000,默认 0)。负的 offsetY 表示向上移动。
w, h 否 字段大小,单位为磅(8 到 1,000)。默认:签名 160×48,姓名缩写 64×40,复选框 14×14,日期 110×20,邮箱 180×20,其他文本 160×20。
required, label 否 与按坐标放置的字段相同。

超出页面的字段会被移回页面内。没有匹配到任何内容的锚点不会生成字段,这通常会在 sendError 中表现为 signer_without_fields。

设置 autoTags: true 后,文档中写的标签会成为字段,归属于 slot 与标签角色相符(完全一致,区分大小写)的收件人:

[[sign:Client]] [[initials:Client]] [[name:Client]] [[date:Client]]
[[text:Client:PO number]] [[check:Client]] [[company:Client]] [[email:Client]]
[[sign:Client;w=180;h=50]] [[text:Client:Notes;optional]]

字段的左上角就是标签的左上角,所以字段会覆盖标签。角色没有对应收件人的标签不会生成字段。

返回 201 Created 和签署请求。刚创建时,它是一份草稿,文档仍在预处理中:

{
"id": "env_01JAB3K9Q7M2X8R4T6V0W1Y2Z3",
"status": "draft",
"finishing": false,
"finalizeFailed": false,
"title": "Service agreement ACME-2026-114",
"createdAt": 1792290600000,
"sentAt": null,
"expiresAt": null,
"completedAt": null,
"documents": [
{
"id": "doc_01JAB3K9RA5C7E9G1H3J5K7M9N",
"name": "Service agreement",
"prepareState": "pending",
"prepareError": null,
"pageCount": null,
"originalSha256": "3b7e0c…",
"preparedSha256": null,
"finalSha256": null,
"deliveredSha256": null
}
],
"recipients": [
{
"id": "rcp_01JAB3K9R2B4D6F8H0J2K4M6P8",
"key": "client",
"role": "signer",
"name": "Dana Lee",
"email": "dana@example.com",
"status": "created",
"routingOrder": 1,
"viewedAt": null,
"completedAt": null,
"declineReason": null
}
],
"auditHead": "a41f9d…",
"sendError": null
}

reach: "link" 的收件人还会有一个 signingUrl(https://sign.automadoc.cc/#/…),仅在此响应中返回:之后的任何读取都不会再返回它,请立即保存。签署请求发出后,该链接才开始生效。每封邀请和提醒邮件都会附带一个新链接,因此链接收件人永远不会收到邮件提醒。

GET https://api.automadoc.cc/api/v1/envelopes/{envelopeId}

返回与创建时相同的结构,反映当前状态。文档预处理期间,请每隔几秒轮询一次;签署请求发出后,每隔几分钟轮询一次就足够了。

status 含义
draft 未发送:文档正在预处理、未要求 send,或由 sendError 说明无法发送的原因。
sent 已发出,等待签署。
completed 所有人均已签署,已签署的文件已就绪。
declined 有签署人拒绝;其 declineReason 位于该收件人中。
voided 您已将其作废。
expired 在所有人签署之前已过 expiresAt。

finishing: true(同时 status: "sent")表示所有人都已签署,已签署的 PDF 正在生成。finalizeFailed: true 表示经过所有重试后仍无法生成:签名都已保留,我们的团队也已收到警报。

收件人的状态依次为 created(尚未轮到)、sent、viewed,然后是 completed 或 declined。cc 收件人从一开始就是 sent。

每份文档都带有每个阶段的 SHA-256:originalSha256(您的文件)、preparedSha256(所有人看到并签署的 PDF)、finalSha256(写入了签名)和 deliveredSha256(您下载的文件:写入了签名,附加证书时还包含证书)。auditHead 是签署请求审计记录中最后一个事件的哈希。任何人都可以用 POST https://api.automadoc.cc/api/verify 和 { "sha256": "…" }(整个文件的小写十六进制值)核对交付的文件,返回结果说明它是否与某个已完成的签署请求一致。

GET https://api.automadoc.cc/api/v1/envelopes?status=completed&since=1792290600000&limit=50
查询参数 作用
status draft、sent、completed、declined、voided 或 expired。
since 仅返回在此时间(Unix 毫秒)或之后更新的签署请求。
limit 1 到 100,默认 25。
cursor 上一页的 nextCursor。

返回 { "envelopes": [ … ], "nextCursor": "…" },按从新到旧排列;最后一页的 nextCursor 为 null。在门户中创建的签署请求,其收件人的 key 为 null。

GET https://api.automadoc.cc/api/v1/envelopes/{envelopeId}/documents/{documentId}/signed
GET https://api.automadoc.cc/api/v1/envelopes/{envelopeId}/certificate
GET https://api.automadoc.cc/api/v1/envelopes/{envelopeId}/combined

signed 是一份已签署的文档;certificate 是单独的完成证书;combined 是合并为一个 PDF 的所有已签署文档(附加证书时证书位于末尾),只为包含两份或以上文档的签署请求生成。这些接口在签署请求变为 completed 后才可用:在此之前,返回 409 和 DOCUMENT_NOT_FOUND。

返回的是一个短期有效的链接,而不是文件本身:

{
"url": "https://api.automadoc.cc/api/esign-files/env_01JAB3K9Q7M2X8R4T6V0W1Y2Z3/final/doc_01JAB3K9RA5C7E9G1H3J5K7M9N.pdf?e=…&d=a&n=…&s=…",
"filename": "Service agreement.pdf",
"expiresAt": 1792306800000,
"sha256": "e5a01c…"
}

请在 15 分钟内获取 url,无需密钥。过期后再请求一次即可获得新链接。sha256 是文件的指纹(对于 signed,即该文档的 deliveredSha256)。每次下载都会记录在审计记录中。已完成签署请求的已签署文件会一直保留,直到有人删除。

POST https://api.automadoc.cc/api/v1/envelopes/{envelopeId}/void
{ "reason": "Replaced by version 2" }

停止一个已发出的签署请求:链接失效,已收到它的收件人会收到邮件通知。reason 为必填(最多 500 个字符)。返回签署请求,此时为 voided。只有已发出且尚未结束的签署请求才能作废。

POST https://api.automadoc.cc/api/v1/envelopes/{envelopeId}/recipients/{recipientId}/remind

recipientId 是收件人的 id(rcp_…),而不是您的 key。立即给收件人发送一封带新链接的邮件;之前邮件中的链接随即失效。仅适用于已轮到的邮件收件人,每 10 分钟最多一次。返回 { "remindedAt": 1792300000000, "channel": "email" }。自动提醒按签署请求的 reminders 设置发送,无需任何调用。

创建一个只有一位签署人的签署请求,把签名放在文字“Client signature:”旁边,把日期放在“Date:”旁边,然后发送。JSON 放在 envelope 部分,PDF 放在名为 contract 的部分:

Terminal window
cat > envelope.json <<'EOF'
{
"title": "Service agreement ACME-2026-114",
"message": "Please review and sign by Friday.",
"timezone": "Asia/Jakarta",
"documents": [{ "name": "Service agreement", "file": "contract" }],
"recipients": [
{ "key": "client", "role": "signer", "name": "Dana Lee", "email": "dana@example.com" }
],
"anchors": [
{ "anchor": "Client signature:", "recipient": "client", "type": "signature", "offsetX": 110, "offsetY": -10 },
{ "anchor": "Date:", "recipient": "client", "type": "date_signed", "offsetX": 40, "occurrence": 1 }
],
"send": true
}
EOF
curl -X POST 'https://api.automadoc.cc/api/v1/envelopes' \
-H "X-Webhook-API-Key: $AUTOMADOC_KEY" \
-F 'envelope=<envelope.json' \
-F 'contract=@contract.pdf;type=application/pdf'

持续跟踪,直到 status 变为 sent(或设置了 sendError),再等到它变为 completed:

Terminal window
curl -s 'https://api.automadoc.cc/api/v1/envelopes/ENVELOPE_ID' \
-H "X-Webhook-API-Key: $AUTOMADOC_KEY"

完成后,获取已签署文档的链接并下载:

Terminal window
url=$(curl -s 'https://api.automadoc.cc/api/v1/envelopes/ENVELOPE_ID/documents/DOCUMENT_ID/signed' \
-H "X-Webhook-API-Key: $AUTOMADOC_KEY" | jq -r .url)
curl -s -o signed.pdf "$url"

同样的创建请求如果用 JSON 发送,就把文件放在 base64 中:"documents": [{ "name": "Service agreement", "base64": "JVBERi0xLjcK…" }]。

需要 Node.js 18 或更高版本。用 AUTOMADOC_KEY=amk_… node sign.mjs 运行:

import { readFile, writeFile } from 'node:fs/promises'
import { createHash } from 'node:crypto'
const API = 'https://api.automadoc.cc'
const KEY = process.env.AUTOMADOC_KEY
async function call(method, path, body) {
const res = await fetch(API + path, {
method,
headers: body ? { 'X-Webhook-API-Key': KEY, 'Content-Type': 'application/json' } : { 'X-Webhook-API-Key': KEY },
body: body ? JSON.stringify(body) : undefined,
})
const json = await res.json()
if (!res.ok) throw new Error(`${res.status} ${json.code}: ${json.error}`)
return json
}
const pdf = await readFile('contract.pdf')
let envelope = await call('POST', '/api/v1/envelopes', {
title: 'Service agreement ACME-2026-114',
documents: [{ name: 'Service agreement', base64: pdf.toString('base64') }],
recipients: [{ key: 'client', role: 'signer', name: 'Dana Lee', email: 'dana@example.com' }],
anchors: [{ anchor: 'Client signature:', recipient: 'client', type: 'signature', offsetX: 110, offsetY: -10 }],
send: true,
})
// The documents are prepared and the fields placed, then the envelope is sent.
while (envelope.status === 'draft' && !envelope.sendError) {
await new Promise((resolve) => setTimeout(resolve, 2000))
envelope = await call('GET', `/api/v1/envelopes/${envelope.id}`)
}
if (envelope.sendError) throw new Error(`Not sent: ${JSON.stringify(envelope.sendError)}`)
console.log(`${envelope.id} is ${envelope.status}`)
// Later (a scheduled job, say): download every signed document of a completed envelope.
export async function downloadSigned(envelopeId) {
const current = await call('GET', `/api/v1/envelopes/${envelopeId}`)
if (current.status !== 'completed') return false
for (const doc of current.documents) {
const link = await call('GET', `/api/v1/envelopes/${envelopeId}/documents/${doc.id}/signed`)
const bytes = Buffer.from(await (await fetch(link.url)).arrayBuffer())
if (createHash('sha256').update(bytes).digest('hex') !== link.sha256) throw new Error('Download damaged')
await writeFile(`${doc.id}.pdf`, bytes)
}
return true
}

错误以 JSON 返回:{ "code": "…", "error": "English text" };如果问题出在请求的某个部分,还会用 path 指明(recipients[1].email)。

HTTP code 何时出现
400 INVALID_REQUEST 请求无效;请查看 path 和 error。
401 API_KEY_MISSING X-Webhook-API-Key 或 Authorization 中没有密钥。
403 API_KEY_INVALID 密钥未知或已吊销,或者是模板自己的密钥。
403 ESIGN_SEND_BLOCKED 提醒:有人举报了贵公司的邮件,审核期间贵公司的发送已暂停。请联系客服。
404 ENVELOPE_NOT_FOUND 贵公司没有这个签署请求。
404 RECIPIENT_NOT_FOUND 提醒:此签署请求中没有这位收件人。
404 DOCUMENT_NOT_FOUND 下载:没有这份文档,或没有这个文件(只有一份文档的签署请求没有 combined 文件)。
404 GENERATION_NOT_FOUND generationId 不是贵公司生成的文档。
409 GENERATION_NOT_COMPLETED 该生成文档尚未完成,或已不在保留期内。
409 DOCUMENT_NOT_FOUND 在签署请求完成之前下载。
409 ENVELOPE_NOT_DRAFT 对从未发送过的签署请求执行作废或提醒。
409 ENVELOPE_CLOSED 对已完成、已拒绝、已作废或已过期的签署请求执行作废或提醒。
409 ENVELOPE_FINISHING 所有人签署后、已签署文件生成期间执行作废或提醒。
409 NOT_ALLOWED 提醒尚未轮到的收件人,或链接收件人。
410 ENVELOPE_CLOSED 签署请求的文件被删除后下载。
413 FILE_TOO_LARGE 文件超过 25 MB,或 multipart 请求超过 26 MB。
413 ENVELOPE_TOO_LARGE base64 文档合计超过 10 MB,或文件合计超过 50 MB。
413 INVALID_REQUEST JSON 请求体超过 14 MB。
415 UNSUPPORTED_FILE 文件不是 PDF、Word、Excel 或 PowerPoint 文件。
429 RATE_LIMITED 该密钥每分钟超过 60 个请求,或该公司每分钟超过 600 份文档。
429 ESIGN_SEND_RATE_LIMITED 提醒:距离上次提醒这位收件人不到 10 分钟。
502 ESIGN_WORKER_UNAVAILABLE 提醒:提醒未能送达。
503 ESIGN_WORKER_UNSUPPORTED 目前无法预处理文档以供签署。请稍后重试;没有创建任何内容。

如果创建请求在保存文档期间被拒绝,草稿及其文件会被删除,不会留下任何半成品。

使用 send: true 时,发送发生在创建请求返回之后,因此发送被拒绝的原因会出现在签署请求的 sendError 中(签署请求保持 draft),而不是以 HTTP 状态返回:

sendError.code 含义
SEND_PROBLEMS 签署请求不完整;problems 列出原因(见下文)。
QUOTA_EXCEEDED 每月额度和所有文档包都已用完(请参阅费用)。
ESIGN_SEND_RATE_LIMITED 免费版:贵公司在过去一小时内已发送 3 个签署请求。任何套餐:一分钟内发送超过 10 次。
ESIGN_RECIPIENT_CAP 这次发送会超过贵公司每天可联系的收件人数(见下文)。
ESIGN_SEND_BLOCKED 有人举报了贵公司的邮件,审核期间贵公司的发送已暂停。请联系客服。
ESIGN_EMAIL_UNAVAILABLE 无法为此签署请求发送邮件。没有发送任何内容,也没有扣费;reach: "link" 的收件人仍可使用。
ESIGN_EMAIL_UNVERIFIED 创建该密钥的人没有已验证的邮箱地址。
ESIGN_ALREADY_PENDING 这份生成文档已在另一个签署请求中等待签署。
INVALID_REQUEST 标签和锚点合计生成了超过 500 个字段,或发生了意外错误。

每个问题的格式为 { "code": "…" };如果涉及某个具体对象,还会带有 documentId、recipientId 或 fieldId(是 ID,不是您的 key):

问题 含义
document_failed 某份文档无法预处理;其 prepareError 说明原因(见下文)。
too_many_pages 所有文档合计超过 300 页。
envelope_too_large 文件合计超过 50 MB,或预处理后的 PDF 合计超过 100 MB。
no_signer 没有角色为 signer 的收件人。
signer_without_fields 某位签署人没有字段:锚点没有匹配到任何内容,或标签的角色没有对应的 slot。
recipient_missing_email 某位邮件收件人没有地址。
recipient_role_unavailable 角色不是 signer 或 cc。
too_many_fields 超过 500 个字段。
field_for_non_signer 字段分配给了 cc 收件人。
field_bad_page 字段的页码超出了其文档的页数。
field_off_page 字段超出了页面,或小于 8 磅。
field_type_unavailable 字段类型不是上面列出的八种之一。

文档的 prepareError 是以下之一:pdf_encrypted(PDF 设有密码保护)、file_too_large(预处理后的 PDF 会超过 50 MB)、too_many_pages、unsupported_file、invalid_file(文件已损坏)、conversion_failed、source_unavailable、timeout 或 internal。

限制 值
每个签署请求的文档数 10
单个文件 25 MB
一个签署请求的文件合计 50 MB
单份预处理后的文档(所有人签署的 PDF) 50 MB
一个签署请求的预处理后文档合计 100 MB
一个签署请求的文档合计页数 300
每个签署请求的收件人数 20
每个签署请求的字段数 500
每个请求的锚点数 50,每个最多匹配 200 次
JSON 请求体 14 MB,其中 base64 文档最多 10 MB
Multipart 请求 26 MB
有效期 发送后 1 到 120 天,默认 30 天
提醒 每 1 到 30 天一次,最多 10 次;默认每 3 天一次,共 3 次
链接锁定前允许输错访问码的次数 5
下载链接 15 分钟
草稿 30 天无改动后删除
已拒绝、已作废和已过期签署请求的文件 关闭 90 天后删除

如需发送超过 26 MB 的文件,请通过 generationId 添加,这样文件不会随请求传输。

发送上限。 没有专业版、也没有 Business 席位的公司,每小时最多发送 3 个签署请求,每天最多联系 20 位收件人(账户创建后的前 24 小时内每天 5 位)。有专业版或 Business 席位时,每天最多可联系 1,000 位收件人。每位收件人都计入,包括 cc 收件人和链接收件人,按滚动的 24 小时计算。每家公司每分钟最多发送 10 个签署请求。

  • 每发出一个签署请求使用一份文档的额度,无论其中包含多少文档和收件人。在发送时计费,之后即使被作废、拒绝或过期也不退还。草稿不收费。
  • AutomaDoc 生成的文档第一次发送时免费:所有文档都来自 generationId 的签署请求不收费,除非其中有文档已在另一个签署请求中发送过,这时按一份文档计费。同时包含生成文档和上传文件的签署请求按一份计费。
  • 由谁支付。 用公司密钥发送的签署请求属于自动化,与文档 API 相同:专业版(或试用期)免费;否则先计入 Business 席位的自动生成额度,然后是每月免费额度,最后是您的文档包。全部用完时,sendError 为 QUOTA_EXCEEDED。Starter 席位属于个人,不涵盖通过 API 发送。

上述发送上限适用于所有套餐。