OpenAPI · REST 参考
REST primitives for every WIDTH OpenAPI call — request envelope, signing, errors, idempotency, configuration, and file upload. Workflow endpoints (KYC, KYB, transactions, monitoring) are documented in their own pages.
请求结构
所有 OpenAPI 调用使用相同的请求结构。接口名称、该接口适用的 API 版本、密钥和签名通过查询参数传递;请求正文使用 JSON。
POST {base_url}?api={apiName}&apiVersion={apiVersion}&apiKey={apiKey}&sign={sign}
Content-Type: application/json
x-domain: {domainId}
{
...request body...
}
| Parameter | Where | Description |
|---|---|---|
api | query | API name, e.g. workflow.apply.submit |
apiVersion | query | 按具体接口指定的版本。workflow.apply.submit 使用 2.0.0;请勿假设所有接口使用同一默认版本。 |
apiKey | query | Your public key (prefixed ak_) |
sign | query | HMAC-SHA256 hex string of the body, keyed by apiSecret |
x-domain | header | Business unit (domain) identifier |
提交工作流
接口:workflow.apply.submit(POST)。用于启动当前已发布工作流的一次执行。使用 apiVersion=2.0.0 时,可选传入 workflowId,以明确指定要执行的已发布工作流。如果 workflowId 为空或未传入,WIDTH 将继续按照 eventType + source 自动路由请求。
API 版本行为
| apiVersion | 行为 |
|---|---|
1.0.0 | 按照 eventType + source 自动路由。 |
2.0.0 | 包含 1.0.0 的全部行为,并支持可选的 workflowId,用于明确指定已发布工作流。如果 workflowId 为空或未传入,则其路由行为与 1.0.0 完全一致。推荐使用。 |
请求正文
{
"eventType": "{eventType}",
"source": "API",
"data": {
"customerId": "demo-customer-001"
},
"workflowId": "{publishedWorkflowId}"
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
eventType | string | 是 | 用于启动或路由工作流的事件类型。 |
source | string | 是 | 请求来源。服务端集成使用 API。 |
data | object | 是 | 工作流业务数据。请包含工作流入口事件所要求的字段。 |
workflowId | string | 否 | 仅适用于 2.0.0。用于指定要执行的已发布工作流。如果为空或未传入,WIDTH 将按照 eventType + source 自动路由。 |
workflowId 传入。响应格式
All responses share the same envelope:
{
"apiCode": 200,
"apiMsg": "OK",
"data": { ... }
}
Errors use the same shape with a non-200 apiCode and a null data field:
{
"apiCode": 999001,
"apiMsg": "SIGN_ERROR",
"data": null
}
Error codes
| Code | Message | Description | Action |
|---|---|---|---|
200 | OK | Success | — |
999000 | GATEWAY_ERROR | General gateway error | Contact support |
999001 | SIGN_ERROR | Signature verification failed | See authentication |
999301 | API_INVALID_REQUEST | Malformed request | Check request body |
999302 | API_NOT_FOUND | API not found | Verify api parameter |
999303 | API_NON_AUTHORIZED | Unauthorized | Check tenant permissions |
999401 | SERVICE_TIME_OUT | Backend timeout | Retry with backoff |
999402 | SERVICE_INVOKE_ERROR | Invocation failed | Retry or contact support |
身份验证
Every request is signed with HMAC-SHA256 over the raw request body. The signature is sent as the sign query parameter.
sign = HmacSHA256(apiSecret, requestBody)
Both the key and body use UTF-8 encoding. The result is a 64-character lowercase hexadecimal string.
import hmac, hashlib
sign = hmac.new(
api_secret.encode('utf-8'),
request_body.encode('utf-8'),
hashlib.sha256
).hexdigest()
const crypto = require('crypto');
const sign = crypto
.createHmac('sha256', apiSecret)
.update(requestBody, 'utf8')
.digest('hex');
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);
apiSecret in client code. Signing must happen on a server you control. The SDKs use a session-scoped sdkToken instead.幂等性
All node-data submission APIs are idempotent by callbackKey. Submitting the same callbackKey multiple times is safe — the workflow advances only once.
Use idempotency for safe retries on network failure or timeouts. Persist your callbackKey with the original request and reuse it on retry.
交互模式
客户端:链式流程
前端根据每次提交响应返回的 nextStep 对象推进。每个步骤会说明下一个节点及界面需要收集的数据。
服务端:状态查询
服务端对服务端的流程在自动处理期间应每 3–5 秒查询一次 workflow.execution.status。当 caseStatus 为 UNASSIGNED、UNDER_REVIEW 或 RETURNED 时,将间隔放宽至 30–60 秒。执行达到终止状态后停止。请参阅 KYC 状态与审核结果及执行状态。
Configuration
Endpoint: prepare.avira.config (POST). Returns reference data used by workflow nodes — country lists, document types, industry codes.
| Key | Description | Used by |
|---|---|---|
particular | Personal / corporate field definitions | Particular nodes |
required-form | Form templates with validation rules | Required Forms nodes |
avira_countries | Country list (ISO codes + names) | Nationality, residence |
avira_document_master | Supported documents per country | OCR & upload |
avira_ssic | Industry classification codes | Industry field |
avira_ssoc | Occupation classification codes | Occupation field |
avira_phone_code | Country phone codes | Phone verification |
avira_entity_types | Corporate entity types | KYB particular |
File upload
Two-step upload: request a short-lived token, then POST the file.
Step 1 — get upload token
Endpoint: storage.upload.token (POST). Body: {}.
{
"apiCode": 200,
"data": {
"uploadToken": "a1b2c3d4...",
"expiresIn": 900
}
}
Tokens are valid for 15 minutes.
Step 2 — upload the file
Multipart:
curl -X POST "${STORAGE_URL}/api/v1/upload/file" \
-F "uploadToken=a1b2c3d4..." \
-F "file=@passport_front.jpg"
Base64 (for in-memory images):
curl -X POST "${STORAGE_URL}/api/v1/upload" \
-H "Content-Type: application/json" \
-d '{
"uploadToken": "a1b2c3d4...",
"image": "data:image/jpeg;base64,/9j/4AAQ...",
"filename": "passport_front.jpg"
}'
Supported types: PNG, JPG, JPEG, GIF, WEBP, TIFF, PDF. Max size: 20 MB.
Error handling & retry strategy
| Scenario | Recommendation |
|---|---|
| Signature error (403) | Do not retry; fix signing implementation |
| Server error (500) | Retry 3× with exponential backoff (1s → 2s → 4s) |
| Status polling | Every 2–5 seconds, max 30 minutes |
| Upload token 401 | Get a new token, retry once |
| OTP verify fail | Resend OTP if max attempts exhausted |
| Network timeout | Safe to retry — all submission APIs are idempotent |