RealDoc异步任务Webhook使用指南

功能说明

RealDoc Webhook用于通知异步文档处理任务的最终状态。当您通过异步文档处理API提交任务后,任务进入SuccessFailure状态时,ZOLOZ会向您配置的回调地址发送HTTP POST请求。

Webhook仅通知任务状态,不包含完整处理结果。收到通知后,请使用transactionId调用异步任务状态或结果查询接口获取详细结果。

开通说明

Webhook按商户和环境开通。如需开通,请联系ZOLOZ客户经理或技术支持,并提供目标环境和商户信息。

使用流程

前提条件

  • 开通Webhook功能和Portal权限:请联系ZOLOZ开通。
    • Portal权限开通后,请退出并重新登录。
    • 当前Webhook管理功能面向Administrator、Operator及具备相关权限的自定义角色开放。
  • 准备接收地址:准备一个可以从公网访问的HTTPS回调地址。

配置步骤

  1. 登录ZOLOZ Portal。
  2. 在左侧导航栏,选择Integration > Webhook,进入Webhook Configuration页面。
  3. 创建Webhook并选择RealDoc Async
  4. 填写配置信息,包括HTTPS回调地址、Secret、摘要算法等,保存后执行测试验证连通性。
  5. 测试成功后启用该配置。
  6. 通过RealDoc异步API提交任务后,ZOLOZ将在任务完成时发送Webhook通知。收到通知后,请使用transactionId查询完整结果。

回调协议

请求概览

项目

内容

Method

POST

Content-Type

application/json

回调地址

Portal中配置的公网HTTPS地址

发送时机

异步任务进入SuccessFailure状态时

请求Header

HTTP Header名称不区分大小写。

Header

说明

X-Payload-Digest

使用Portal中配置的Secret对原始请求Body计算得到的HMAC签名(十六进制字符串)。

X-Payload-Digest-Alg

签名算法,支持HMAC_SHA256_HEXHMAC_SHA512_HEX

请求Body

示例:

copy
{
    "transactionId": "R000000202607211713541766****", 
    "status": "Success", 
    "productType": "REALDOC_DOCUMENT_EXTRACTION"
}

字段说明:

字段

说明

transactionId

异步任务的唯一标识,与异步上传接口响应中的任务标识一致,用于幂等处理和结果查询。

status

任务的最终状态,SuccessFailure

productType

RealDoc产品类型。支持以下取值:

  • REALDOC_FORGERY_DETECTION
  • REALDOC_DOCUMENT_EXTRACTION
  • REALDOC_DOCUMENT_INSIGHT
  • REALDOC_CROSS_MATCHING
  • REALDOC_DOCUMENT_PARSING

Java接收与验签示例

本示例适用于Java 8和Spring Boot。验签时需注意:

  • 算法支持:验签支持HMAC_SHA256_HEXHMAC_SHA512_HEX两种签名算法。
  • 关键要求:验签时必须使用HTTP收到的原始Body,请勿对Body进行格式化、反序列化或重新序列化,否则会导致签名不一致。
copy
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.EnumMap;
import java.util.Map;

import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/webhooks")
public class RealDocWebhookController {

    private static final Logger log = LoggerFactory.getLogger(RealDocWebhookController.class);

    private static final String HEADER_DIGEST     = "X-Payload-Digest";
    private static final String HEADER_DIGEST_ALG = "X-Payload-Digest-Alg";

    private static final String ALG_HMAC_SHA256_HEX = "HMAC_SHA256_HEX";
    private static final String ALG_HMAC_SHA512_HEX = "HMAC_SHA512_HEX";

    private final Map<HmacAlgorithms, HmacUtils> hmacUtilsMap = new EnumMap<>(HmacAlgorithms.class);

    public RealDocWebhookController(@Value("${realdoc.webhook.secret:}") String secret) {
        hmacUtilsMap.put(HmacAlgorithms.HMAC_SHA_256, new HmacUtils(HmacAlgorithms.HMAC_SHA_256, secret));
        hmacUtilsMap.put(HmacAlgorithms.HMAC_SHA_512, new HmacUtils(HmacAlgorithms.HMAC_SHA_512, secret));
    }

    @PostMapping(value = "/realdoc", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Void> receive(@RequestBody String rawBody, @RequestHeader(HEADER_DIGEST) String digest,
            @RequestHeader(HEADER_DIGEST_ALG) String algorithm) {

        HmacAlgorithms hmacAlg = resolveAlgorithm(algorithm);
        if (hmacAlg == null) {
            log.warn("Unsupported digest algorithm: {}", algorithm);
            return ResponseEntity.badRequest().build();
        }

        String expected = hmacUtilsMap.get(hmacAlg).hmacHex(rawBody);
        boolean valid = MessageDigest.isEqual(expected.getBytes(StandardCharsets.UTF_8), digest.getBytes(StandardCharsets.UTF_8));
        if (!valid) {
            log.warn("Webhook signature verification failed, algorithm={}", algorithm);
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }

        // Process the event idempotently by transactionId.

        return ResponseEntity.ok().build();
    }

    private HmacAlgorithms resolveAlgorithm(String algorithm) {
        switch (algorithm) {
            case ALG_HMAC_SHA256_HEX:
                return HmacAlgorithms.HMAC_SHA_256;
            case ALG_HMAC_SHA512_HEX:
                return HmacAlgorithms.HMAC_SHA_512;
            default:
                return null;
        }
    }
}

注意事项

  • 接收成功后,请尽快向ZOLOZ返回HTTP 2xx状态码。如果业务处理耗时较长,建议将耗时的业务逻辑转移至内部队列异步处理。
  • 当ZOLOZ未收到2xx响应或发生超时、网络异常时,可能触发重试,同一通知可能多次送达。请使用transactionId幂等处理。
  • Webhook投递失败不影响RealDoc任务结果,您仍可以定期调用状态查询和结果查询接口获取任务最终结果。
  • Webhook仅由客户通过异步API提交的任务触发,Portal体验中心发起的任务不会触发Webhook通知。
  • 未开通或未配置Webhook不影响原有异步API的正常使用,您仍可通过状态查询和结果查询接口进行轮询。
  • Secret应保存在Portal和您的密钥管理系统中,不要记录到日志中,也不要提交到代码仓库。