Skip to main content

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, API version, key, and signature are passed as query parameters; the body is JSON.

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

{
  ...request body...
}
ParameterWhereDescription
apiqueryAPI name, e.g. workflow.apply.submit
apiVersionqueryAPI version (default 1.0.0)
apiKeyqueryYour public key (prefixed ak_)
signqueryHMAC-SHA256 hex string of the body, keyed by apiSecret
x-domainheaderBusiness unit (domain) identifier

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

CodeMessageDescriptionAction
200OKSuccess
999000GATEWAY_ERRORGeneral gateway errorContact support
999001SIGN_ERRORSignature verification failedSee authentication
999301API_INVALID_REQUESTMalformed requestCheck request body
999302API_NOT_FOUNDAPI not foundVerify api parameter
999303API_NON_AUTHORIZEDUnauthorizedCheck tenant permissions
999401SERVICE_TIME_OUTBackend timeoutRetry with backoff
999402SERVICE_INVOKE_ERRORInvocation failedRetry 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);
Never expose 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 at relaxed intervals (1–5 minutes) until a terminal state. See execution statuses.

Configuration

Endpoint: prepare.avira.config (POST). Returns reference data used by workflow nodes — country lists, document types, industry codes.

KeyDescriptionUsed by
particularPersonal / corporate field definitionsParticular nodes
required-formForm templates with validation rulesRequired Forms nodes
avira_countriesCountry list (ISO codes + names)Nationality, residence
avira_document_masterSupported documents per countryOCR & upload
avira_ssicIndustry classification codesIndustry field
avira_ssocOccupation classification codesOccupation field
avira_phone_codeCountry phone codesPhone verification
avira_entity_typesCorporate entity typesKYB particular
Cache configuration locally. The data changes infrequently. Refresh daily or on a deploy signal.

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

ScenarioRecommendation
Signature error (403)Do not retry; fix signing implementation
Server error (500)Retry 3× with exponential backoff (1s → 2s → 4s)
Status pollingEvery 2–5 seconds, max 30 minutes
Upload token 401Get a new token, retry once
OTP verify failResend OTP if max attempts exhausted
Network timeoutSafe to retry — all submission APIs are idempotent