要用 DocuSign API 按自定义字段值搜索信封,调用 Envelopes: listStatusChanges 端点(GET /restapi/v2.1/accounts/{accountId}/envelopes),带上格式为 字段名=值 的 custom_field 查询参数,并同时提供 DocuSign 在每次信封搜索中都要求的日期范围参数。例如,custom_field=Region=West 返回名为 Region 的信封自定义字段值为 West 的信封;custom_field=Region=%25West%25(即 %West% 的 URL 编码形式)则匹配值中只要包含 "West" 的信封。custom_field 正是为这项任务设计的专用过滤器,远比把某个日期范围内的所有信封全部拉回来、再在自己的代码里逐个匹配要高效。
动手之前有一点必须先知道:旧的 Search Folders 端点(GET /restapi/v2.1/accounts/{accountId}/search_folders/{searchFolderId})在 API v2.1 中已被标记为弃用。新的集成应基于 Envelopes: listStatusChanges 提供的 custom_field、search_text 和日期过滤器来构建信封搜索。本文会完整走一遍流程:自定义字段如何写入信封、请求本身、响应处理、通配符、分页,以及最容易让首次尝试翻车的失败模式。
简要答案:一个 GET 请求加两个过滤条件
最小可用请求需要三样东西:端点、一个 custom_field 过滤条件,以及 from_date(DocuSign 的信封搜索文档注明,from_date 和 to_date 是每次信封搜索操作的必填参数)。以下是 cURL 形式的请求:
```bash
curl -X GET "https://demo.docusign.net/restapi/v2.1/accounts/{accountId}/envelopes" \
-H "Authorization: Bearer {accessToken}" \
-H "Accept: application/json" \
--get \
--data-urlencode "custom_field=Region=West" \
--data-urlencode "from_date=2026-07-01T00:00:00Z" \
--data-urlencode "status=completed"
```
这个 URL 里有三个细节值得注意:
- 值里面含有等号。
custom_field=Region=West必须正确编码,让第二个=在查询字符串中保留下来。像上面那样使用--data-urlencode,或者手写编码后的字符串custom_field=Region%3DWest,都可以。 - 日期应采用带显式时区偏移的 ISO 8601 格式。 DocuSign 建议使用
2026-07-01T00:00:00Z这类显式偏移;不带偏移时会按服务器时区解释,你的时间窗口会被悄悄挪动。 status可选但很有用。 它接受逗号分隔的当前状态列表,如completed、sent、delivered、declined或voided,any则匹配所有状态。
响应是一个 JSON 对象,其 envelopes 数组包含匹配到的信封摘要,含 envelopeId、status、emailSubject。如果摘要里没有你需要的全部信息,可以对单个信封跟进调用 GET /restapi/v2.1/accounts/{accountId}/envelopes/{envelopeId}/custom_fields,它会返回该信封的自定义字段,含 fieldId、name、value。
如果你还在熟悉身份验证、集成密钥和 demo 环境这些基础,建议先把它们逐一跑通,再把本文的写法接入生产代码。
能搜的前提:先搞懂信封自定义字段怎么工作
搜不到从未存进去的东西。在 DocuSign 中,信封自定义字段是挂在信封本身的元数据,不属于某个文档或某个签署人。它分两种:文本自定义字段(发送人手动输入或通过 API 设置的自由文本)和列表自定义字段(从预定义列表中选择的值)。通常由管理员在账户层级定义,再在创建或发送信封时填上具体值。
通过 API 创建信封时,在 customFields 对象里设置它们:
```json
{
"status": "sent",
"emailSubject": "Master Services Agreement",
"customFields": {
"textCustomFields": [
{
"name": "ClientID",
"value": "CLI-12345",
"show": "true",
"required": "false"
}
]
}
}
```
这对 ClientID: CLI-12345,就是之后 custom_field=ClientID=CLI-12345 要匹配的内容。这个设计带来两个实际影响:
- 一致性是你自己的责任。 搜索匹配的是发送人和集成实际写入的内容。一个系统写
CLI-12345,另一个写cli_12345,只有严格的命名纪律才能保证搜索可靠。把规范落在集成代码里,而不是寄托在人的记性上。 - 信封自定义字段不同于 tab(文档上的表单字段)。 签署人在文档字段里填的值,
custom_field是过滤不到的。要查这些值,需要导出信封的表单数据后在本地匹配;将已签署信封的 tab 与表单数据导出为 JSON 的指南详细介绍了这条流水线。
另外注意,文本自定义字段的值上限为 100 个字符,把它们当作索引键(ID、区域代码、案件编号)来用,而不是自由文本存储。
分步构建请求
下面是多数团队实际会用的完整流程——一个基于 requests 的 Python 函数:
```python
import requests
def search_envelopes_by_custom_field(access_token, base_url, account_id,
field_name, field_value,
from_date, to_date=None):
url = f"{base_url}/restapi/v2.1/accounts/{account_id}/envelopes"
params = {
"custom_field": f"{field_name}={field_value}",
"from_date": from_date,
}
if to_date:
params["to_date"] = to_date
response = requests.get(
url,
headers={
"Authorization": f"Bearer {access_token}",
"Accept": "application/json",
},
params=params,
)
response.raise_for_status()
return response.json()["envelopes"]
results = search_envelopes_by_custom_field(
access_token=TOKEN,
base_url="https://demo.docusign.net",
account_id=ACCOUNT_ID,
field_name="ClientID",
field_value="CLI-12345",
from_date="2026-01-01T00:00:00Z",
)
for env in results:
print(env["envelopeId"], env["status"], env.get("emailSubject"))
```
因为 requests 会自动对参数做 URL 编码,custom_field=ClientID=CLI-12345 中内嵌的 = 会被妥善处理。如果你用其他语言手工拼 URL,记得显式编码(ClientID%3DCLI-12345)。
对匹配精度要求高时,建议加一道客户端校验:遍历返回的信封,在信封详情里确认自定义字段的名称和值完全相符之后,再据此采取动作。这能防住两种意外:使用通配符时的部分匹配误伤,以及历史信封上的字段名漂移。
进一步过滤:状态、日期范围、文件夹与分页
单一过滤条件很少对应真实的业务问题。Envelopes: listStatusChanges 支持多种参数组合,可以干净地映射到常见场景:
关于这些配套参数的说明:
from_date/to_date限定信封状态发生变化的日期范围。除非你改传envelope_ids或transaction_ids,否则from_date是必填的。status与from_to_status的区别:status按信封的当前状态过滤;from_to_status限定你关心的是窗口内的哪一次状态变更。逻辑上不可能成立的组合(例如用delivered限定词搭配当前状态created)会在不查数据库的情况下直接返回空列表——所以一个令人困惑的空结果,有时是逻辑错误,而不是数据缺失。- 文件夹范围:
folder_ids和folder_types把搜索限制在completed、draft、recyclebin等逻辑文件夹内。 - 用户范围:
user_id或user_filter把结果收窄到某个特定用户作为发送人或收件人的信封。 - 分页:用
count(每次调用返回的条数)配合start_position(起始的零基索引)翻页遍历大结果集,而不是一次请求全部。 - 裁剪响应体:
exclude参数可以在不需要时把收件人或 PowerForm 数据等类别从响应中剔除。
如果你在评估一个重度依赖 API 的集成的总体成本,DocuSign 定价与成本分析拆解了 API 套餐和限额通常的构成方式。
精确匹配、通配符还是宽泛文本搜索:选对过滤器
DocuSign 提供三种机制,选错是“我的搜索不工作”最常见的原因:
通配符形式是最容易被忽略的:百分号包在值的两侧,手工拼查询字符串时要 URL 编码为 %25。custom_field=ApplicationId=%25DocuSign%25 能匹配 ApplicationId 值中任意位置包含 "DocuSign" 的信封。
代价是精度。search_text 是最钝的工具:搜一个客户 ID,会连带命中主题、收件人邮箱或邮件正文里碰巧含有这个字符串的所有信封。把 search_text 留给“帮我找那个信封”式的交互功能;在自动化工作流里,凡是驱动下游逻辑的精确键,都用 custom_field。
常见错误与调用前排查清单
当自定义字段搜索什么都返回不了、或返回了错误结果时,先过一遍这份清单,再怀疑 API:
from_date存在且覆盖该信封。 信封可能比你的窗口更老,或者缺失的时区偏移悄悄挪动了边界。- 字段名完全匹配。 自定义字段名是账户层级定义的大小写敏感字符串;
ClientID和ClientId是两个不同的字段。 - 值的编码正确。 内嵌的
=需要%3D,字面量%通配符需要%25。 - 状态组合在逻辑上成立。 检查当前
status值能否与你的日期范围和任何from_to_status限定词共存。 - 该字段是信封自定义字段,不是文档 tab。 签署人填写的 tab 值对
custom_field不可见;这类值要导出表单数据后在客户端过滤。 - 账户没搞错。 多账户环境中,经常出现搜索的是账户 A、而信封在账户 B 的情况。
- 令牌有效且未过期。 搜索调用返回
401几乎总是 OAuth 过期而非查询问题;400则指向参数格式错误。
对于要把已签署协议从 DocuSign 归档留存的团队,有一点要提醒:搜索只是留存策略的一半,另一半是可靠的导出与本地备份机制,两者缺一不可。
规模化建议:高并发场景下推送优于轮询
搜索是拉取模式,而定时轮询在大多数调用没有新结果时会白白消耗 API 额度。对于需要对信封事件做出反应的工作流,例如“客户 X 的合同一完成就更新 CRM”,DocuSign Connect webhook 会在事件发生时把状态更新推送到你的端点。一种常见的混合设计是:webhook 作为主触发器,custom_field 搜索作为对账路径——webhook 处理日常流程,每晚一次的搜索扫描兜住任何因事件遗漏而落下的信封。这种扫描同时还兼任审计工具,因为它从源数据重新推导出“每个客户有多少信封在待签署”的视图。
如果你对信封数据的需求已经从搜索走向更完整的合同智能,那已经是另一个层面的议题,值得单独评估。而如果你选型电子签名平台时最看重开发者体验,面向软件开发者的中国电子签名 REST API 盘点比较了各平台如何处理本文这类集成工作。
用 Nota Sign 构建可搜索的签署工作流
靠元数据追信封,背后是更深一层的需求:你的协议从创建那天起,就应该是可检索的结构化数据。集成团队带着这种“检索优先”的设计诉求找到的,正是 FaDaDa(法大大)旗下的全球电子签名平台 Nota Sign。平台支持 100 多个国家和地区的签署,其区域数据中心让亚太地区的签署流量贴近它所服务的交易对手。
如果你的路线图包含围绕可搜索、可过滤的信封数据重建协议流水线,欢迎通过 Nota Sign 联系页面 告诉我们你的集成需求。团队会围绕你的业务量、覆盖区域,以及信封数据需要馈入的系统来界定讨论范围。








