跳到主要内容

回调通知说明

回调通知是电子签平台在合同、印章、模板等业务发生状态变化时,主动向贵方服务推送消息的机制。贵方无需轮询查询,即可实时感知业务动态。

本文将按照以下顺序,带您从零完成回调的接入:

① 了解回调机制② 选择要监听的场景③ 配置加密与校验④ 对照结构体与样例解析数据⑤ 设计可靠的接收架构⑥ 排查常见问题(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 即开启消息加密,去掉即关闭(发送明文回调消息)。建议开启加密以确保数据安全。

解密步骤

  1. 对收到数据 {"encrypt":"base64后的密文"} 中的 base64 后的密文进行 Base64 解码,得到原始密文
  2. 原始密文进行对称解密:算法为 AES-256-CBC,密钥为电子签提供的 CallbackUrlKey,IV 取 CallbackUrlKey 值的前 16 位,数据采用 PKCS#7 填充。
  3. 解密后得到的即为输入参数的 JSON 格式数据。

解密代码可参考 解密代码 demo

2. 回调消息校验

签名验证 token

新建第三方应用时,如果配置了签名验证 token(可选参数),电子签的回调请求会在 header 中附带签名参数 [Content-Signature],贵方可据此验证请求确实来自电子签,防止伪造。

原理可参考:GitHub Webhooks 安全实践

校验步骤

当贵方回调服务接收到回调时:

  1. 取出 header 中的 [Content-Signature]
  2. 按下方代码验证签名:验证通过则继续处理,不通过则忽略该请求。
// 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 序列化:

参数名称参数类型参数描述
MsgIdString消息唯一 ID,为 32 位字符串,用于唯一确定本消息
MsgTypeString消息类型,标识本消息由哪个场景发送,如 FlowStatusChange 标识合同状态变更,详见各场景回调
MsgVersionString消息版本,固定为 ThirdPartyApp
MsgData结构体消息数据,各消息类型的结构体不同,详见各场景回调中的 MsgData 结构体定义

2. 密文回调消息结构体

设置了回调加密 key 时,回调服务接收到的请求为该密文结构体的 JSON 序列化,解密后才是上方的明文回调消息结构体

参数名称参数类型参数描述
encryptString加密后的消息体(需通过回调加密 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=="}

此处使用回调加密 keyTencentEssEncryptTestKey12345678,参考解密代码 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 次全部失败,平台将认为该消息无法送达并丢弃此消息。请务必保证回调服务的可用性。

回调延时多长?

回调在对应事件发生后立即执行,含处理与网络请求耗时,一般在几百毫秒左右。

具体延时取决于网络状况、服务器负载等因素。若长时间未收到回调,请先检查贵方回调服务是否正常;确认正常后仍无回调,可联系客服处理。