Error handling
Every failure throws a typed EkycError carrying the HTTP status and the
parsed API error envelope:
import { EkycError } from '@drukverify/ekyc-sdk-js';
try {
await client.fraud.detect(image);
} catch (e) {
if (e instanceof EkycError) {
console.log(e.status); // e.g. 400
const err = (e.body as any)?.error;
console.log(err?.type); // stable machine-readable code
console.log(err?.message); // human-readable detail
console.log(err?.request_id); // quote this to support
console.log(err?.doc_url); // documentation for this error
}
}
The API's error contract is { error: { type, message, request_id, doc_url } }.
Codes you should branch on include:
| type | meaning |
|---|---|
validation_error | malformed request; the message names the field |
invalid_key / revoked_key / expired_token | credential problems; only expired_token is fixed by minting a new token |
feature_disabled / feature_not_assigned | the feature isn't enabled for your tenant |
unsupported_image_format | not a decodable JPEG, PNG, WebP, TIFF, BMP or HEIC |
image_too_large | a side is over 40 megapixels; resize and resend |
no_face_detected / multiple_faces_detected / low_quality_face | face-input problems on the face endpoints; prompt a retake |
no_face / multiple_faces / low_image_quality | the same on the liveness endpoint |
frame_replayed / challenge_token_invalid | liveness frames already scored, or a stale challenge token; capture fresh frames and mint a new challenge |
rate_limited | back off for retry_after_ms and retry |
A liveness check that ran but did not pass is not an error: it is a
200 with is_live: false and a reason such as
challenge_action_not_detected. See
Liveness checks.
Timeouts surface as EkycError with status: 0 and message
Request timed out (configurable via timeout). The SDK does not retry on
its own. A request_id accompanies every response; logging it alongside
your own correlation ids makes support turnaround immediate.
The full error catalogue is in the Errors concept page.