回调通知说明
回调通知是电子签平台在合同、印章、模板等业务发生状态变化时,主动向贵方服务推送消息的机制。贵方无需轮询查询,即可实时感知业务动态。
本文将按照以下顺序,带您从零完成回调的接入:
① 了解回调机制 → ② 选择要监听的场景 → ③ 配置加密与校验 → ④ 对照结构体与样例解析数据 → ⑤ 设计可靠的接收架构 → ⑥ 排查常见问题(FAQ)
一. 回调说明
在开始之前,请先了解回调的基本约定。这些是贵方接收端必须满足的前提条件:
| 项目 | 说明 |
|---|---|
| 回调地址 | 在企业应用管理的第三方应用中配置(配置方式见下方 回调 FAQ → 回调地址是否支持更改或删除) |
| 请求方式 | 电子签平台的回调均为 POST 请求。如果收到的是 GET 请求,请确认回调地址是否存在 http 到 https 的转发 |
| 数据格式 | JSON 格式请求 ("Content-Type":"application/json"),数据样式:{"encrypt":"base64后的密文"} |
| 回调成功条件 | 只要贵方返回 httpcode 200,平台即认为回调成功,不再重发本条消息 |
返回 200 是回调成功的唯一判定标准。若贵方处理失败但仍返回 200,平台不会重试;反之未返回 200 则会按重试机制重发(详见 FAQ)。
如何验证回调地址是否可用?
如果已配置回调 URL 却收不到通知,可先在外网环境用下方 curl 命令做一次连通性自测。地址能正常返回 httpcode 200 即表示可用:
curl https://tsign.tencent.com/callback -H 'Content-type: application/json' -X POST -d '{}'
# 请将 https://tsign.tencent.com/callback 替换成贵方配置的回调地址

若仍收不到回调,建议在接收端记录收到的原始请求日志,便于排查问题。
二. 回调场景
确认接收端就绪后,接下来选择贵方需要监听的业务场景。
通知类型以 MsgType 字段做区分,按业务主要分为以下几类。请根据实际需求点击对应文档,查看该场景下的具体字段定义:
三. 回调加密与校验
选定场景后,为保障数据安全,强烈建议开启加密和签名校验。本节介绍两项可选的安全能力及其接入方式。
若希望先看一遍完整流程,可观看视频:回调通知配置和接收端代码编写示例(视频)
1. 回调消息加解密
回调加密 key
新建应用号时,如果配置了回调加密 key(可选参数),电子签的回调请求体会被加密,贵方需用该 key 解密才能得到真正的回调消息。
配置回调加密 key 即开启消息加密,去掉即关闭(发送明文回调消息)。建议开启加密以确保数据安全。
解密步骤

- 对收到数据
{"encrypt":"base64后的密文"}中的 base64 后的密文进行 Base64 解码,得到原始密文。 - 对原始密文进行对称解密:算法为 AES-256-CBC,密钥为电子签提供的 CallbackUrlKey,IV 取 CallbackUrlKey 值的前 16 位,数据采用 PKCS#7 填充。
- 解密后得到的即为输入参数的 JSON 格式数据。
解密代码可参考 解密代码 demo
2. 回调消息校验
签名验证 token
新建第三方应用时,如果配置了签名验证 token(可选参数),电子签的回调请求会在 header 中附带签名参数 [Content-Signature],贵方可据此验证请求确实来自电子签,防止伪造。
原理可参考:GitHub Webhooks 安全实践
校验步骤
当贵方回调服务接收到回调时:
- 取出 header 中的 [Content-Signature]。
- 按下方代码验证签名:验证通过则继续处理,不通过则忽略该请求。
// payload_body 为接收到的消息体内容
// verify_token 为在第三方应用中配置的 "签名验证 token"
// content_signature 为从请求头部中取得的 Content-Signature 的值
def verify_signature(payload_body,content_signature,verify_token):
signature = 'sha256=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), verify_token, payload_body)
return halt 500, "Signatures didn't match!" unless Rack::Utils.secure_compare(signature, content_signature)
payload_body 为整个原始消息体(即 {"encrypt":"base64后的密文"}),验签时请不要做任何更改,否则签名将无法匹配。
四. 通用结构体
完成解密与校验后,贵方即可按下述结构体解析回调数据。根据是否开启加密,接收到的原始请求分为两种:
1. 明文回调消息结构体
未设置回调加密 key 时,回调服务接收到的请求即为该结构体的 JSON 序列化:
| 参数名称 | 参数类型 | 参数描述 |
|---|---|---|
| MsgId | String | 消息唯一 ID,为 32 位字符串,用于唯一确定本消息 |
| MsgType | String | 消息类型,标识本消息由哪个场景发送,如 FlowStatusChange 标识合同状态变更,详见各场景回调 |
| MsgVersion | String | 消息版本,固定为 ThirdPartyApp |
| MsgData | 结构体 | 消息数据,各消息类型的结构体不同,详见各场景回调中的 MsgData 结构体定义 |
2. 密文回调消息结构体
设置了回调加密 key 时,回调服务接收到的请求为该密文结构体的 JSON 序列化,解密后才是上方的明文回调消息结构体:
| 参数名称 | 参数类型 | 参数描述 |
|---|---|---|
| encrypt | String | 加密后的消息体(需通过回调加密 key 解密得到明文回调消息结构体的 JSON 序列化) |
五. 回调样例
下面通过一个完整样例,直观展示上述结构体在真实回调中的样子:从收到加密数据,到解密还原为明文消息。
1. 密文回调消息
POST /callback HTTP/1.1
Host: www.esstest.com
User-Agent: Go-http-client/1.1
Content-Length: xxx
Content-Type: application/json
Accept-Encoding: gzip
{"encrypt":"uXm2LDbslypT/mTXnKJynaj7riwJt356nGXvs/MszFshjs591sgduXpQpYXGNfox6U3Mk65Q+vCOo8CAHoMgVJVHEJl1ZmHvR1ocYNvquuVcwOK+/QN4zuH1NbkEtACLsVFgmG/B9L9pV3+i6u/uCTcFFF6LyxcgB4V7OHBwRoOUSLi/LqBTshNstW5W/mDzBPZUwed9e3Kk1Cmt7VUn+z22kyF0AoHuGuvUtVId7n+TAda7eTSty6nkFtxXk/DhvZPMeFXyN61aOa8nKSdL9bAosjjkrMYevlWhDsGeINDtSjLNmkzlEs9ZpOEMCHy8bG9vHMRuyFdW1hjBBTM/Tw=="}
此处使用回调加密 key:TencentEssEncryptTestKey12345678,参考解密代码 Demo 解密后可获取以下明文:
⚠️ 该回调加密 key 仅用于本测试样例。
{
"MsgId": "yDwf4UUckpsjeox1URAyCMBHv7W1zDbP",
"MsgType": "OrgAuth",
"MsgVersion": "ThirdPartyApp",
"MsgData": {
"ApplicationId": "yDwftUUckpsrmwz5UEfbpqAAAAAAAAAA",
"ProxyOrganizationOpenId": "MockOpenId",
"ProxyOperatorOpenId": "MockUserOpenId",
"AuthSuccess": true
}
}
2. 明文回调消息
若未配置回调加密 key,回调服务将直接收到如下明文消息:
POST /callback HTTP/1.1
Host: www.esstest.com
User-Agent: Go-http-client/1.1
Content-Length: xxx
Content-Type: application/json
Accept-Encoding: gzip
{"MsgId":"yDwf4UUckpsjeox1URAyCMBHv7W1zDbP","MsgType":"OrgAuth","MsgVersion":"ThirdPartyApp","MsgData":{"ApplicationId":"yDwftUUckpsrmwz5UEfbpqAAAAAAAAAA","ProxyOrganizationOpenId":"MockOpenId","ProxyOperatorOpenId":"MockUserOpenId","AuthSuccess":true}}
六. 回调最佳实践
了解数据结构后,还需要一套可靠、可追溯、可补偿的接收架构,才能在生产环境中稳定处理回调。我们推荐采用 统一回调接收服务 + MQ 异步解耦 的方案:

该方案的五个核心要点:
- 统一接收:由一个统一回调服务集中接收并校验所有第三方回调,避免各业务重复实现接收与验签逻辑。
- 日志留存:收到回调后先记录完整回调日志,为问题排查和事后追溯提供依据。
- MQ 解耦:回调统一投递至消息队列(MQ),各业务方按需独立消费,互不影响。
- 异常补偿:业务处理异常或回调丢失时,可基于回调日志查询并重新投递,实现补偿重放。
- 快速响应:回调服务在完成消息的可靠接收(落库/入队)后立即返回 200,把耗时的业务处理交给下游异步执行,避免业务逻辑拖慢响应、触发第三方重试。
核心原则是「接收」与「处理」分离:接收端只做校验、落库、入队并快速返回 200;真正的业务逻辑由下游异步消费。这样既能满足平台的超时与成功判定要求(详见回调说明与 FAQ),又能借助日志与 MQ 实现丢失补偿。
七. 回调 FAQ
接入过程中的常见问题汇总如下。
回调地址是否支持同时配置多个?
支持。每个第三方应用下只能有一个回调地址,根据您的需求,不同地址可以配置相同或不同的回调加密 key、签名验证 token。
回调地址是否支持更改或删除?
支持。您可在控制台的企业应用管理 → 第三方应用配置中修改回调地址。

回调配置后多长时间生效?
配置完成后立即生效。若修改了回调加密 key 或签名验证 token,请确保贵方回调服务已同步支持这两个新的 key。
为什么收到 ALL(合同签署完成)后,又收到了 PART(合同签署中)或 INIT(合同创建)通知?
以单方签署合同为例,FlowCallbackStatus 状态一般由合同签署中或合同创建变为合同签署完成。
少量回调可能因状态变化间隔短、重发或网络传输等原因,出现到达顺序不一致的小概率情况。建议贵方从代码层面做适当控制,例如:状态更新为合同签署完成后,不再回退为合同签署中或合同创建。
电子签发送回调的超时时间是多久?
超时时间为 5 秒。
回调失败后最大重试多少次?重试机制如何?
最大重试 36 次,重试间隔随次数递增:
1 秒、2 秒、3 秒、4 秒、5 秒、10 秒、15 秒、20 秒、25 秒、30 秒、35 秒、40 秒、45 秒、50 秒、55 秒、1 分、2 分、3 分、4 分、5 分、6 分、7 分、8 分、9 分、10 分、15 分、25 分、35 分、45 分、55 分、1 时、2 时、3 时、4 时、5 时、6 时
若 36 次全部失败,平台将认为该消息无法送达并丢弃此消息。请务必保证回调服务的可用性。
回调延时多长?
回调在对应事件发生后立即执行,含处理与网络请求耗时,一般在几百毫秒左右。
具体延时取决于网络状况、服务器负载等因素。若长时间未收到回调,请先检查贵方回调服务是否正常;确认正常后仍无回调,可联系客服处理。