OpenAPI · REST reference
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.
Request envelope
Every OpenAPI call uses the same request envelope. The endpoint name, endpoint-specific API version, key and signature are passed as query parameters; the body is 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 | Version defined by the endpoint. Use 2.0.0 for workflow.apply.submit; do not assume one global default. |
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 |
Submit a workflow
Endpoint: workflow.apply.submit (POST). Starts an execution using the currently published workflow. With apiVersion=2.0.0, you can optionally provide workflowId to explicitly select a published workflow. If workflowId is empty or omitted, WIDTH auto-routes the request by eventType + source.
API version behaviour
| apiVersion | Behaviour |
|---|---|
1.0.0 | Auto-routes by eventType + source. |
2.0.0 | Everything in 1.0.0, plus an optional workflowId to explicitly select the published workflow. If workflowId is empty or omitted, routing behaves exactly like 1.0.0. Recommended. |
Request body
{
"eventType": "{eventType}",
"source": "API",
"data": {
"customerId": "demo-customer-001"
},
"workflowId": "{publishedWorkflowId}"
}
| Field | Type | Required | Description |
|---|---|---|---|
eventType | string | Yes | Event type used to start or route the workflow. |
source | string | Yes | Origin of the request. Server-side integrations use API. |
data | object | Yes | Business payload for the workflow. Include the fields required by the workflow's entry event. |
workflowId | string | No | 2.0.0 only. Specifies the published workflow to execute. If empty or omitted, WIDTH auto-routes by eventType + source. |
workflowId.Response format
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 |
Authentication
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.Idempotency
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.
Interaction model
Client-side: chain-driven flow
Your frontend is driven by the nextStep object returned in each submission response. Each step tells your UI which node is next and what to collect.
Server-side: status polling
For server-to-server flows, poll workflow.execution.status every 3–5 seconds during automated processing. When caseStatus is UNASSIGNED, UNDER_REVIEW or RETURNED, reduce polling to every 30–60 seconds. Stop at a terminal state. See KYC status and review outcomes and execution statuses.
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 |