跳轉到主要內容

OpenAPI · REST 參考

REST 請求結構、身份驗證、工作流生命週期、錯誤處理、配置與文件上傳。

快速入門

基礎地址

環境 網關 URL
測試環境 https://api-gateway-platform.width.com/gateway
生產環境 https://api-gateway.width.com/gateway

請求格式

POST {base_url}?api={apiName}&apiVersion={apiVersion}&apiKey={apiKey}&sign={sign}
Content-Type: application/json
x-domain: {domainId}

{JSON body}
參數 位置 必填 描述
api 查詢參數 是 API 名稱
apiVersion 查詢參數 是 按接口而定 — workflow.apply.submit 推薦 2.0.0,其餘用 1.0.0(見 工作流生命週期 API)
apiKey 查詢參數 是 您的 API key
sign 查詢參數 是 請求體的 HMAC-SHA256 簽名
x-domain 請求頭 是 您的業務 domain ID

發起工作流

接口: workflow.apply.submit POST

按 eventType + source 路由到當前已發佈(PUBLISHED)的工作流併發起執行。

apiVersion 版本

apiVersion 說明
1.0.0 按 eventType + source 自動路由
2.0.0 在 1.0.0 基礎上支持可選 workflowId,顯式指定要執行的已發佈工作流;workflowId 爲空時行爲與 1.0.0 完全一致。推薦使用。

請求

{
  "eventType": "KYC_EVENT",
  "source": "API",
  "data": {
    "customerId": "demo-customer-001",
    "fullName": "ZHANG SAN",
    "dateOfBirth": "1990-01-01",
    "nationality": "CN"
  },
  "workflowId": ""
}
字段 類型 必填 描述
eventType string 是 事件類型:KYC_EVENT / KYB_EVENT / TRANSACTION_EVENT / WEB3_TRANSACTION_EVENT / MANUAL_CASE_EVENT,以租戶開通的事件爲準。前兩項在平臺界面上顯示爲 KYC 和 KYB,那是界面顯示名;接口裏要傳 KYC_EVENT 和 KYB_EVENT。MANUAL_CASE_EVENT 用於把主體提交做名單篩查,在平臺界面上顯示爲 人工。
source string 是 來源。服務端對接固定填 API。
data object 是 業務數據。customerId 必填且必須對同一客戶保持穩定(workflow.apply.query 依賴它做恢復查詢);其餘字段依工作流入口事件的字段定義。
workflowId string 否 僅 2.0.0。指定已發佈工作流 ID;爲空則按事件自動路由。

響應

{
  "apiCode": 200,
  "apiMsg": "OK",
  "data": {
    "code": 200,
    "message": null,
    "executionId": "exec-7208f03b931e4897",
    "status": "EXECUTING",
    "requestId": "...",
    "sync": false
  }
}
字段 類型 描述
executionId string 執行實例 ID。請務必持久化 — 後續用它輪詢 workflow.execution.status。
status string 初始狀態(EXECUTING / SUBMITTED)。
sync boolean 是否同步執行;同步模式下 output 直接攜帶決策結果。
code int 200 = 正常;403 = 額度不足(billing blocked)。
額度 — submit 是唯一計費的接口。data.code 返回 403 表示該 eventType 的額度已用盡;不要盲目重試 — 請聯繫管理員充值或調整額度。
提交字段表記錄 KYC_EVENT、KYB_EVENT、TRANSACTION_EVENT、WEB3_TRANSACTION_EVENT 和 MANUAL_CASE_EVENT,具體以租戶開通情況爲準。此列表不視爲完整枚舉:持續監控章節還使用 PERIODIC_FLOW_EVENT,其是否應列入提交枚舉仍待工程團隊確認。
customerId 契約:通用提交參考要求 data.customerId 必填,且同一客戶保持穩定,以供 workflow.apply.query 恢復執行。Web3 字段表卻將其標爲可選。在工程團隊確認 Web3 要求前,請在 Web3 請求中提供穩定的 customerId,不要依賴省略該字段的行爲。

工作流 ID 位置:在 WIDTH One Platform 打開 Workflow,在工作流列表中複製工作流名稱旁顯示的 Workflow ID,並在使用 apiVersion 2.0.0 時通過 workflowId 傳入。

響應格式

成功:

{
  "apiCode": 200,
  "apiMsg": "OK",
  "data": {}
}

錯誤:

{
  "apiCode": 999001,
  "apiMsg": "SIGN_ERROR",
  "data": null
}
分兩層讀。HTTP 狀態碼是傳輸層 — 4xx/5xx 表示網關未受理請求(無 data)。HTTP 200 時再看 apiCode 判斷網關結果(200 = 成功)。部分業務接口會在 data 下再包一層 { code, data, msg } 業務信封 — 業務數據在 data.data(見註冊客戶示例)。

按順序讀取響應:先看 HTTP 狀態,再看 apiCode;若接口使用業務信封,再看 data.code 和 data.data。僅 apiCode 爲 200 不代表業務成功,仍須檢查該接口的業務結果。

錯誤碼

apiCode apiMsg 描述 處理方式
200 OK 成功 —
999000 GATEWAY_ERROR 網關通用錯誤 聯繫技術支持
999001 SIGN_ERROR 簽名驗證失敗 參見身份驗證
999301 API_INVALID_REQUEST 請求格式錯誤 檢查請求體
999302 API_NOT_FOUND API 名稱未找到 檢查 api 參數
999303 API_NON_AUTHORIZED 無此 API 權限 檢查 apiKey 權限
999304 RATE_LIMIT_TRY_AGAIN 超出頻率限制 等待後重試
999401 SERVICE_TIME_OUT 後端服務超時 退避重試
999402 SERVICE_INVOKE_ERROR 後端調用失敗 重試;持續失敗則聯繫技術支持
999403 SERVICE_NOT_FOUND 後端服務不可用 聯繫技術支持
999404 SERVICE_RESPONSE_FORMAT_ERROR 後端返回格式異常 聯繫技術支持
999501 REQUEST_API_EXCEED_LIMIT API 調用配額已用盡 聯繫技術支持提升配額

身份驗證

簽名計算

sign = HmacSHA256(apiSecret, requestBody)

密鑰和請求體均使用 UTF-8 編碼。結果爲 64 位小寫十六進制字符串。 簽名必須基於 HTTP body 的原始字節計算。

代碼示例

Java:

Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(apiSecret.getBytes("UTF-8"), "HmacSHA256"));
byte[] hash = mac.doFinal(requestBody.getBytes("UTF-8"));
String sign = HexFormat.of().formatHex(hash); // Java 17+

Python:

import hmac, hashlib

sign = hmac.new(
    api_secret.encode('utf-8'),
    request_body.encode('utf-8'),
    hashlib.sha256
).hexdigest()

Node.js:

const crypto = require('crypto');
const sign = crypto.createHmac('sha256', apiSecret)
    .update(requestBody, 'utf8').digest('hex');
切勿在瀏覽器或移動端代碼中暴露 apiSecret。請在您控制的服務器上簽名請求。SDK 客戶端使用會話級 sdkToken。

冪等性

所有節點數據提交接口均基於 callbackKey 冪等。重複提交相同 callbackKey 是安全的 — 僅首次成功提交生效,因此網絡超時後可放心重試。

交互模型

工作流生命週期 API

工作流生命週期 API 是純服務端對接路徑:由你的後端發起一個事件、輪詢執行狀態與 Case(案件,一次審覈的記錄單元)審覈結論,並在請求丟失或被重試時查詢該客戶是否已有進行中的執行。三個接口構成一個閉環。

它與 KYC / KYB 章節記錄的節點驅動 SDK 路徑不同:那裏客戶端逐個節點提交數據,這裏由平臺從頭到尾跑完整個已發佈工作流,你只需發起並輪詢。

流程概覽

  1. 發起
  2. 輪詢狀態
  3. 審覈結論

workflow.apply.query 位於這個循環之前,作爲恢復路徑:當一次 submit 可能已經發生過(超時或上游重試)時先調用它,避免重複提交。

計費

API 用途 計費
workflow.apply.submit 發起工作流執行 是 — 按 eventType 扣對應額度
workflow.execution.status 按 executionId 查執行狀態與 Case 結論 否
workflow.apply.query 查該客戶是否已有執行 否
三個接口與其餘 OpenAPI 接口共用同一網關基礎地址、同一套 query-string 請求信封(api / apiVersion / apiKey / sign)加 x-domain 請求頭,以及同樣的請求體 HMAC-SHA256 簽名。基礎地址(Staging api-gateway-platform.width.com/gateway / 生產 api-gateway.width.com/gateway)與請求格式見 OpenAPI 參考 → 快速入門,完整簽名規則見 身份驗證 章節。

查詢狀態與審覈結論

接口: workflow.execution.status POST

只讀接口 — 不觸發執行、不計費。executionId 按租戶(及 x-domain)校驗歸屬,無法跨租戶查詢。使用 apiVersion 1.0.0。

請求

{ "executionId": "exec-7208f03b931e4897" }
字段 類型 必填 描述
executionId string 是 workflow.apply.submit 返回的執行實例 ID。

響應

{
  "apiCode": 200,
  "apiMsg": "OK",
  "data": {
    "executionId": "exec-7208f03b931e4897",
    "status": "COMPLETED",
    "caseNo": "C001443",
    "caseStatus": "REJECTED",
    "riskScore": 45.0,
    "resolvedAt": 1784714818000
  }
}
字段 類型 描述
status string 執行狀態:RUNNING / WAITING / COMPLETED / FAILED / 取消狀態值:待確認。
caseNo string 關聯 Case 編號(C%06d);尚未生成 Case 時爲空。
caseStatus string Case 處理狀態:UNASSIGNED(隊列待分配)/ UNDER_REVIEW(審覈員處理中)/ RETURNED(退回重做)/ OTHER_GROUP(本組已處理完,流程仍在其他組/節點進行)/ APPROVED / REJECTED / CLOSED(已完成,流程結束);無 Case 時爲空。輪詢退出條件依據此字段。
riskScore number 風險評分(0–100);無則爲空。
resolvedAt long 結案時間(epoch 毫秒);未結案爲空。
currentNode 等 object SDK 流程控制用的內部字段(currentNode / output / pendingCallbackTask),服務端集成請忽略。
data 爲空字符串時,表示 executionId 不存在,或不屬於當前 apiKey 所在的租戶/domain。

狀態語義

status caseStatus 含義
RUNNING / WAITING 空 執行中(含等待信息採集),尚未生成 Case。
RUNNING / WAITING UNASSIGNED / UNDER_REVIEW / RETURNED 執行停在 review 節點等待人工處理 — 繼續輪詢。
RUNNING / WAITING OTHER_GROUP 當前 Case 所在組已處理完,流程仍在其他組/節點進行 — 繼續輪詢。
COMPLETED / 取消狀態值:待確認 APPROVED / REJECTED / CLOSED 已出結論,流程結束。
FAILED — 執行失敗,請聯繫支持並提供 executionId。

各階段響應示例

階段 1 — 自動節點執行中,Case 尚未生成(到達決策節點前的短暫窗口):

{ "apiCode": 200, "apiMsg": "OK",
  "data": { "executionId": "exec-xxxx", "status": "RUNNING" } }

無 caseStatus 字段 → 尚未生成 Case,繼續輪詢。

階段 2 — Case 已生成,等待人工處理:

{ "apiCode": 200, "apiMsg": "OK",
  "data": { "executionId": "exec-xxxx", "status": "RUNNING",
            "caseNo": "C001286", "caseStatus": "UNASSIGNED", "riskScore": 49.17 } }

人工處理期間 caseStatus 反映進度:UNASSIGNED(隊列待分配)→ UNDER_REVIEW(審覈員領取後);退回重做時爲 RETURNED。

階段 3 — 已出結論(人工審覈或自動決策):

{ "apiCode": 200, "apiMsg": "OK",
  "data": { "executionId": "exec-xxxx", "status": "COMPLETED",
            "caseNo": "C001443", "caseStatus": "REJECTED", "riskScore": 45.0,
            "resolvedAt": 1784714818000 } }
多審覈組流程中,當前 Case 處理完後若整體流程仍在其他組/節點進行,caseStatus 爲 OTHER_GROUP — 請繼續輪詢至 caseStatus 變爲終態(APPROVED / REJECTED / CLOSED)。

輪詢退出條件

每次執行到達決策節點後都會生成 Case(人工審覈 → UNASSIGNED / UNDER_REVIEW;自動通過/拒絕/關閉 → 直接產生終態 Case),因此:

caseStatus in {APPROVED, REJECTED, CLOSED}
OR status == FAILED
OR status == CONFIRMED_CANCELLATION_ENUM
輪詢節奏 — 間隔 3–5 秒;進入人工處理階段(caseStatus ∈ {UNASSIGNED, UNDER_REVIEW, RETURNED})可放寬至 30–60 秒。

恢復查詢(防重 / 斷點恢復)

接口: workflow.apply.query POST

按 eventType + source + customerId 查詢該客戶是否已有執行。只讀 — 不觸發新執行、不計費。使用 apiVersion 1.0.0。

請求

{
  "eventType": "KYC_EVENT",
  "source": "API",
  "customerId": "demo-customer-001"
}
字段 類型 必填 描述
eventType string 是 與 submit 時一致。
source string 是 與 submit 時一致。
customerId string 是 與 submit 時 data.customerId 一致(必須對同一客戶保持穩定)。

響應

{
  "apiCode": 200,
  "apiMsg": "OK",
  "data": {
    "code": 200,
    "executionId": "exec-7208f03b931e4897",
    "status": "RUNNING"
  }
}
命中情況 executionId status 建議動作
客戶已審批通過 最近一次 COMPLETED 執行 APPROVED 不要重複提交。
存在進行中的執行 該執行 RUNNING 轉輪詢 workflow.execution.status。
未命中(被拒/無記錄) 空 — 可正常調用 submit。
customerId 穩定性 — customerId 必須與 submit 時 data.customerId 完全一致,且對同一客戶長期穩定;否則恢復查詢無法命中。

錯誤碼

層級 碼 說明 處理建議
網關 apiCode 200 成功(業務結果看 data.code) —
網關 apiCode 999302 API 名稱錯誤 檢查 api / apiVersion
網關 apiCode 999305 apiKey 無效或已停用 覈對 API & Integration 頁面的 API Key
網關 apiCode 999001 簽名錯誤 檢查 sign 計算(body 原文簽名、無多餘換行)
網關 apiCode 999401 服務超時 稍後重試;持續出現請聯繫支持
data.code 400 參數缺失 檢查請求 body
data.code 403 額度不足(僅 submit) 聯繫管理員充值/調整額度
data 爲空 — execution 不存在或不屬於當前租戶/domain(僅 status) 覈對 executionId 與 apiKey / x-domain;x-domain 爲必填 header,請始終顯式攜帶

代碼示例

以下 curl 命令是各接口的調用示例。執行 submit 前先檢查恢復查詢結果:APPROVED 表示不要重複提交;RUNNING 表示繼續輪詢狀態。提交超時後先查詢再重試,因爲 submit 會計費。Python 示例運行前必須配置已由工程團隊確認的取消狀態枚舉。

curl(完整閉環)

API_KEY="ak_xxx"
API_SECRET="sk_xxx"
DOMAIN_ID="{domainId}"
BASE_URL="https://api-gateway-platform.width.com/gateway"

# HMAC-SHA256 sign helper / 签名助手
sign() { printf "%s" "$1" | openssl dgst -sha256 -mac HMAC -macopt key:"$API_SECRET" | sed 's/^.* //'; }

# 0. (optional) recovery query — dedup before submit / 恢复查询防重
BODY='{"eventType":"KYC_EVENT","source":"API","customerId":"demo-customer-001"}'
curl -s -X POST "${BASE_URL}?api=workflow.apply.query&apiVersion=1.0.0&apiKey=${API_KEY}&sign=$(sign "$BODY")" \
  -H "Content-Type: application/json" -H "x-domain: ${DOMAIN_ID}" -d "$BODY"

# 1. submit / 发起工作流
BODY='{"eventType":"KYC_EVENT","source":"API","data":{"customerId":"demo-customer-001","fullName":"ZHANG SAN"},"workflowId":""}'
curl -s -X POST "${BASE_URL}?api=workflow.apply.submit&apiVersion=2.0.0&apiKey=${API_KEY}&sign=$(sign "$BODY")" \
  -H "Content-Type: application/json" -H "x-domain: ${DOMAIN_ID}" -d "$BODY"
# -> record data.executionId / 记下 data.executionId

# 2. poll status / 轮询执行状态
BODY='{"executionId":"exec-7208f03b931e4897"}'
curl -s -X POST "${BASE_URL}?api=workflow.execution.status&apiVersion=1.0.0&apiKey=${API_KEY}&sign=$(sign "$BODY")" \
  -H "Content-Type: application/json" -H "x-domain: ${DOMAIN_ID}" -d "$BODY"

Python(輪詢循環)

import hashlib, hmac, json, os, time, requests

GATEWAY = "https://api-gateway-platform.width.com/gateway"
API_KEY = os.environ["WIDTH_API_KEY"]
API_SECRET = os.environ["WIDTH_API_SECRET"]
DOMAIN_ID = os.environ["WIDTH_DOMAIN_ID"]
# Supply only the cancellation enum verified by WIDTH engineering.
# Do not guess between the conflicting spellings in the reference.
CANCELLED_STATUS = os.environ["WIDTH_CONFIRMED_CANCEL_STATUS"]

def call(api, version, payload):
    body = json.dumps(payload, separators=(",", ":"))
    signature = hmac.new(API_SECRET.encode(), body.encode(), hashlib.sha256).hexdigest()
    response = requests.post(GATEWAY,
        params={"api": api, "apiVersion": version, "apiKey": API_KEY, "sign": signature},
        headers={"Content-Type": "application/json", "x-domain": DOMAIN_ID},
        data=body, timeout=30)
    response.raise_for_status()
    result = response.json()
    if result.get("apiCode") != 200:
        raise RuntimeError(result)
    data = result.get("data")
    if isinstance(data, dict) and data.get("code", 200) != 200:
        raise RuntimeError(data)
    return data

identity = {"eventType": "KYC_EVENT", "source": "API", "customerId": "demo-customer-001"}
recovered = call("workflow.apply.query", "1.0.0", identity)
if recovered and recovered.get("status") == "APPROVED":
    print(recovered)
else:
    if recovered and recovered.get("status") == "RUNNING":
        execution_id = recovered["executionId"]
    else:
        submitted = call("workflow.apply.submit", "2.0.0", {
            "eventType": identity["eventType"], "source": identity["source"],
            "data": {"customerId": identity["customerId"], "fullName": "ZHANG SAN"},
            "workflowId": ""})
        execution_id = submitted["executionId"]
        # Persist execution_id before polling; recover after an interrupted submit.
    while True:
        state = call("workflow.execution.status", "1.0.0", {"executionId": execution_id})
        if not isinstance(state, dict):
            raise RuntimeError("Verify executionId, apiKey and x-domain; no execution returned")
        if state.get("caseStatus") in ("APPROVED", "REJECTED", "CLOSED") or state.get("status") in ("FAILED", CANCELLED_STATUS):
            print(state)
            break
        time.sleep(30 if state.get("caseStatus") in ("UNASSIGNED", "UNDER_REVIEW", "RETURNED") else 5)

常見問題

Q:submit 超時了,不確定是否已發起,怎麼辦?
不要直接重試 submit(會重複計費)。先調 workflow.apply.query:命中 RUNNING / APPROVED 則拿回 executionId 繼續輪詢;未命中再重新 submit。
Q:status 查不到剛提交的 execution(data 爲空)?
確認與提交時使用同一個 apiKey 與 x-domain——接口按租戶和 domain 校驗歸屬,跨 domain 查詢返回空 data。
Q:執行長時間停在 RUNNING / WAITING 是異常嗎?
不一定。停在 review 節點等待人工處理時執行狀態不會變爲終態,此時 caseStatus 爲 UNASSIGNED / UNDER_REVIEW / RETURNED。以 caseStatus 判斷處理進度。
取消狀態契約待確認:生命週期參考使用 CANCELED,KYC 參考使用 CANCELLED。確認取消後應停止輪詢;部署依賴取消狀態的代碼前,請向 WIDTH 工程團隊確認接口實際返回的枚舉值。此處不將任一拼寫認定爲最終契約。

配置

在啓動工作流前,獲取平臺配置數據(國家列表、證件類型、表單模板等)。

接口: prepare.avira.config POST

{
  "keys": "particular,avira_ssic,avira_ssoc,avira_countries,avira_document_master,avira_document_default_rule,required-form,avira_phone_code,avira_entity_types,ownership_structure_layer,transaction_behaviour,product_service_complexity,source_of_wealth,avira_source_of_funds"
}

配置項

Key 描述 使用方
particular 個人/企業信息字段定義 Particular 節點 (KYC & KYB)
required-form 帶驗證規則的表單模板 Required Forms 節點
avira_countries 國家列表 (ISO 代碼 + 名稱) 國籍、居住國等
avira_document_master 各國支持的證件類型 OCR 及證件上傳
avira_document_default_rule 默認證件要求 必傳文件節點
avira_ssic 行業分類代碼 行業字段
avira_ssoc 職業分類代碼 職業字段
avira_phone_code 國際區號 手機驗證
avira_entity_types 企業實體類型 KYB 企業信息
ownership_structure_layer 股權結構層級設置 KYB 工作流
transaction_behaviour 交易行爲類別 KYB 表單
product_service_complexity 產品/服務複雜度類別 KYB 表單
source_of_wealth 財富來源選項 KYC/KYB 表單
avira_source_of_funds 資金來源選項 KYC/KYB 表單
緩存 — 配置數據變更頻率低,建議本地緩存並每日或按需刷新。

文件上傳

需要 S3 URI 的接口(證件、照片等),需先通過此接口上傳文件。

步驟 1 — 獲取上傳令牌

接口: storage.upload.token POST

請求體: {}。令牌有效期 15 分鐘。

響應:

{
  "apiCode": 200,
  "data": {
    "uploadToken": "a1b2c3d4e5f6...",
    "expiresIn": 900
  }
}

步驟 2 — 上傳文件

存儲服務地址:

環境 URL
測試環境 https://api-gateway-platform.width.com/storage
生產環境 https://api-gateway.width.com/storage

Multipart 上傳:

curl -X POST "${STORAGE_URL}/api/v1/upload/file" \
  -F "uploadToken=a1b2c3d4e5f6..." \
  -F "file=@passport_front.jpg"

Base64 上傳:

curl -X POST "${STORAGE_URL}/api/v1/upload" \
  -H "Content-Type: application/json" \
  -d '{
    "uploadToken": "a1b2c3d4e5f6...",
    "image": "data:image/jpeg;base64,/9j/4AAQ...",
    "filename": "passport_front.jpg"
  }'

響應:

{
  "apiCode": 200,
  "data": {
    "url": "s3://workflow-kyc/tenantImages/2026-04-16/abc123.jpg",
    "filename": "passport_front.jpg",
    "content_type": "image/jpeg",
    "size": 245760
  }
}
S3 URI 是內部引用,非公開可訪問的 URL,請勿直接通過此 URI 下載文件。
支持格式: PNG, JPG, JPEG, GIF, WEBP, TIFF, PDF — 大小限制: 20 MB
令牌過期 (HTTP 401)? 重新獲取令牌後重試上傳。

錯誤處理與重試策略

場景處理方式
SIGN_ERROR / 999001修復簽名,不要在未修正時重試。
999304等待限流恢復後重試。
HTTP 500 / 999401最多重試三次,按 1 秒、2 秒、4 秒指數退避;若 submit 可能已被受理,先用 workflow.apply.query 恢復。
data.code = 403請管理員充值或調整事件額度,不要盲目重試。
上傳令牌 HTTP 401獲取新的上傳令牌,再重試上傳一次。
OTP 驗證達到最大驗證次數後重新發送 OTP。
節點提交超時節點數據提交可使用相同 callbackKey 重試;不要將此保證推廣至 workflow.apply.submit。
輪詢間隔:自動處理時爲 3–5 秒,人工處理時爲 30–60 秒。OTHER_GROUP 時繼續輪詢,直至案件狀態爲 APPROVED、REJECTED 或 CLOSED;FAILED 或確認取消時停止。指南另有通用的 30 分鐘輪詢上限,與較長的人工審覈存在衝突。超過該時長的停止策略待工程團隊確認;不要將計時器到期解釋爲審批通過或拒絕。