开放平台接入说明

说明如何完成开放平台固定审查能力的接入与联调。

这项能力适合什么场景

如果你希望在另一个产品里直接调用 BidRisk 的招标审查或合同审查能力,而不是让用户手动进入主平台操作,那么当前开放平台就是最合适的接入方式。

当前已开放两个固定能力:

  • tender_review.v1
  • contract_review.v1

接入形态固定为:

  • workspace
  • 完全异步 run
  • webhook + result pull

接入前需要准备什么

在开始联调前,需要先完成应用开通并获取接入凭证。

通常包括:

  1. 开通应用接入
  2. 获取 API Key
  3. 如需接收回调,获取 Webhook 签名密钥

当前凭证发放不通过开放接口完成。

第一步:创建 Workspace

workspace 是开放平台的资料容器。

请求示例:

curl -X POST "http://localhost:8000/platform/v1/workspaces" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: ${BIDRISK_API_KEY}" \
  -d '{
    "external_ref": "erp-project-001",
    "title": "XX 项目审查"
  }'

调用成功后会返回一个 workspace_id,后续上传、状态轮询和能力运行都围绕这个 workspace 进行。

第二步:上传文件

平台提供两种上传方式。

方式一:TUS 断点续传(推荐用于大文件)

适合大型 PDF 或网络不稳定的环境。

先获取当前工作区的上传配置:

curl -X POST "http://localhost:8000/platform/v1/workspaces/${WORKSPACE_ID}/upload-config" \
  -H "X-API-Key: ${BIDRISK_API_KEY}"

平台会返回:upload_urlupload_tokenproject_iduser_id

上传示例(使用 tus-js-client):

const upload = new tus.Upload(file, {
  endpoint: uploadConfig.upload_url,
  headers: { "Upload-Token": uploadConfig.upload_token },
  metadata: {
    filename: file.name,
    project_id: String(uploadConfig.project_id),
    user_id: String(uploadConfig.user_id),
    upload_token: uploadConfig.upload_token,
  },
});
upload.start();

方式二:标准 Multipart 上传(简单直观)

适合常规大小文件(如 < 50MB)或无法使用 TUS 客户端的场景。

直接调用以下接口:

curl -X POST "http://localhost:8000/platform/v1/workspaces/${WORKSPACE_ID}/files" \
  -H "X-API-Key: ${BIDRISK_API_KEY}" \
  -F "file=@/path/to/your/file.pdf"

成功返回:

{
  "id": 123,
  "filename": "file.pdf",
  "parse_status": "pending",
  "file_size": 1048576
}

第三步:等待资料就绪

文件上传完成后,不代表可以立刻发起审查。还需要等待平台完成解析与准备状态检查。

轮询接口:

curl "http://localhost:8000/platform/v1/workspaces/${WORKSPACE_ID}/status" \
  -H "X-API-Key: ${BIDRISK_API_KEY}"

建议至少满足以下条件后再发起 run:

  • is_prepare_ready = true
  • 已有至少一个 parse_status = parsed 的文件
  • 发起招标审查时,已识别出招标文件,或 recommended_tender_file_id 不为空
  • 发起合同审查时,至少已有一个 doc_stage = contract 的已解析文件

第四步:创建异步 Run

curl -X POST "http://localhost:8000/platform/v1/runs" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: ${BIDRISK_API_KEY}" \
  -d '{
    "workspace_id": "'"${WORKSPACE_ID}"'",
    "capability_code": "tender_review.v1",
    "callback_url": "https://example.internal/api/bidrisk/webhook"
  }'

说明:

  • 当前支持 tender_review.v1contract_review.v1
  • callback_url 可选
  • 返回的 run_id 是后续轮询和回调幂等处理的关键标识

第五步:获取结果

方式一:轮询 run 状态

curl "http://localhost:8000/platform/v1/runs/${RUN_ID}" \
  -H "X-API-Key: ${BIDRISK_API_KEY}"

开放平台当前使用以下状态:

  • queued
  • running
  • succeeded
  • failed

方式二:拉取结果

curl "http://localhost:8000/platform/v1/runs/${RUN_ID}/result" \
  -H "X-API-Key: ${BIDRISK_API_KEY}"

成功时会返回四类核心信息:

  • summary
  • dimensions
  • findings
  • evidences

如果 run 还没结束,会返回:

  • error_code = run_not_completed

第六步:接收 Webhook

如果创建 run 时传入了 callback_url,平台会在 run 进入终态后回调接收端。

当前支持两个事件:

  • capability_run.completed
  • capability_run.failed

请求头包括:

  • X-BidRisk-Webhook-Timestamp
  • X-BidRisk-Webhook-Signature
  • X-BidRisk-Webhook-Event

签名算法:

  • 原文:timestamp + "." + request_body
  • 算法:HMAC-SHA256
  • 输出格式:v1=<hex_digest>

Python 验签示例:

import hashlib
import hmac


def verify_bidrisk_webhook(secret: str, timestamp: str, body: bytes, signature: str) -> bool:
    expected = hmac.new(
        secret.encode("utf-8"),
        timestamp.encode("utf-8") + b"." + body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(f"v1={expected}", signature)

常见阻断原因

创建 run 时,最常见的阻断并不是接口错误,而是资料尚未满足执行条件。当前常见值包括:

  • no_files
  • files_processing
  • no_parsed_files
  • missing_tender_file
  • missing_contract_file

这些错误通常意味着:

  • 文件还没上传
  • 文件刚上传完,还在解析
  • 还没有可用的招标文件或合同文件

当前边界

第一阶段明确边界如下:

  • 仅支持固定能力 tender_review.v1contract_review.v1
  • 不支持自定义 Agent
  • 不支持用户自定义规则
  • 不支持公开发放 API Key
  • 结果交付方式固定为轮询和 webhook

建议的接入顺序

如果你准备做一次最小联调,建议按下面顺序:

  1. 完成应用开通并获取 API Key
  2. 创建一个 workspace
  3. 上传一份对应场景的核心文件
  4. 轮询 workspace/status 直到解析完成
  5. 创建 tender_review.v1contract_review.v1 run
  6. 轮询 runs/{id} 或接收 webhook
  7. 拉取 runs/{id}/result

如果当前页面没有直接解决你的问题,建议回到左侧目录,按业务任务继续浏览相关专题。