Skip to Content
DocsErrors

Errors & troubleshooting

Every Valyd error is machine-readable: a stable code string plus an HTTP status, and every response carries an X-Request-Id header — quote it to support (never API keys or tokens). Read the status first (it tells you the category), then the code (the exact cause).

Contacting support

Include: the X-Request-Id header value, the session/event id if relevant, a timestamp, and the endpoint called. Never send API keys, tokens, or the person’s identity data — support will never ask for them.

1. Error shapes

Login / account APIs (/api/auth/...) return the envelope:

{ "success": false, "error": { "code": "invalid_token", "message": "Session expired. Please login again." } }

OIDC token endpoint (/api/auth/oidc/token) returns standard top-level OAuth errors:

{ "success": false, "error": { "code": "invalid_grant", "message": "Invalid or expired authorization code" } }

Verification API (/api/v2/...) errors carry the code in error with check context where relevant.

2. What the HTTP status means

StatusCategoryTypical causes
400Bad requestMissing/malformed parameter, invalid scope, expired code
401Not authenticatedWrong client_id/secret, missing/expired token, bad API key
402Payment requiredWallet balance / quota exhausted — top up in the console
403Not allowedMissing scope, app not permitted for this user, consent declined
404Not foundWrong workflow/session/resource id, or it belongs to another project
409ConflictDuplicate — e.g. the member already exists on your roster
410GoneRemoved legacy endpoint (TPSSO) — migrate to /api/auth/oidc/*
422Rejected inputImage/selfie quality, face rescan required, validation failure
429Rate limitedToo many requests — back off and retry after the window
5xxOur sideRetry with backoff; if it persists, contact support

3. Complete code catalog

Generated from the API source — 147 codes. Do not edit by hand; run node scripts/gen-error-catalog.mjs.

CodeHTTPMeaning / fix
access_denied403The user declined, or the app is not permitted for this account.
account_dob_unavailable422This Valyd account has no verified date of birth.
account_not_found404No Valyd account matches that token.
activation_failed500, 503Activation failed.
already_exists409E2E encryption is already active for this device
already_paired409This device is already paired and has E2E keys
app_default_protected422The default app cannot be deleted. Set another app as default first.
back_image_not_found404Back image not found
cache_clear_failed400Failed to clear caches:
callback_not_allowed422callback must exactly match an active, approved HTTPS webhook destination for this project.
challenge_expired400The liveness instruction expired — please try again.
challenge_required400This device must complete challenge flow before login. Call POST /api/auth/face/challenge, then send c, d, s, and face_image.
client_not_found404Client not found
code_expired410The one-time code has expired
database_error500Failed to store device keys
decrypt_failed500Could not open the managed payload
deletion_failed500Could not delete your account. Please try again.
denied403User denied the request
device_already_paired409This device is already paired
device_key_unknown410This browser’s device key is no longer registered. Please register this device again.
device_mismatch400device_id does not match
device_not_found404Device not registered or not linked to a user
empty_face_feature400Empty face feature from SDK
endpoint_not_found
endpoint_removed410You are calling a removed legacy TPSSO endpoint — migrate to /api/auth/oidc/*.
engine_unreachable503Verification engine did not respond. Please retry.
expired410Request expired
face_feature_extraction_failed400Failed to extract face features
face_match_failed500Face match failed
face_match_unavailable502Could not verify your selfie right now. Please try again.
face_mismatch403Face did not match
face_not_enrolled409No face is enrolled on this account
face_not_matched403Face does not match logged-in user
face_not_verified403Face was not verified for this tracking ID
face_required409A face check is required to release identity data
face_rescan_required422We could not confidently recognize you. Please rescan your face.
failed_to_extract_id_portrait_feature
feature_extraction_failed400Feature extraction failed
feature_failed502Feature extraction failed
feature_size_mismatch
forbidden403Invalid internal auth
frames_required400The demo needs a 3-8 frame live burst from your camera.
front_image_id_required400front_image_id is required
front_image_not_found404Front image not found
idempotency_in_progress409A request with this Idempotency-Key is still being processed. Retry shortly.
idempotency_key_reused422This Idempotency-Key was already used with a different request body.
identity_locked403Your identity is verified. Only your email and phone number can be changed. Contact support if something else is wrong.
image_not_found404Image not found
image_too_large413That photo is too large to upload. Please use a smaller image (under 20 MB).
insufficient_scope403The access token lacks a required scope (openid is required for OIDC resource calls).
invalid_activation404This activation link is invalid or has expired.
invalid_api_key401Invalid verification API key.
invalid_audience
invalid_challenge403Invalid or expired challenge, or signature verification failed
invalid_challenge_result403Invalid challenge result
invalid_client401Check client_id/client_secret and that the app is active in the Developer Portal.
invalid_client_metadata400client_name must be between 1 and 120 characters
invalid_config500AGENT_API_KEY not configured
invalid_date400Invalid expire_at format
invalid_feature400Invalid face vector
invalid_frames400Live verification needs at least 3 frames; send one selfie for single-click mode.
invalid_grant400, 401Code/refresh token expired, already used, or issued to another client — restart the flow.
invalid_idp_response
invalid_image400, 422A selfie is required.
invalid_recovery_phrases403Invalid recovery phrases
invalid_redirect_uri400redirect_uris (non-empty array) is required
invalid_request400, 401, 404, 422A required parameter is missing or malformed — compare against the reference.
invalid_scope400Enable the scope for your app in the Developer Portal before requesting it.
invalid_session400Session has no user_ref (pollus_id)
invalid_state409Share request already decided
invalid_status400Invalid status
invalid_token401, 403Token missing/expired — refresh it or sign the user in again.
kyc_required400Complete ID verification before verifying the license.
legacy_ocr_failed
license_not_found400, 404CPR license not found
limit_reached422Vault item limit reached
liveness_unavailable502Could not check your selfie right now. Please try again.
logo_invalid422Logo must be an image data URL.
logo_too_large422Logo image is too large. Please use a smaller file.
misconfigured500Invalid signing key
misconfigured_oidc_endpoints
missing_dob400A date of birth is required (provide dob or run id-verification first).
missing_document400Upload a selfie before running liveness.
missing_parameter400Provide valyd_id or vendor_data.
no_existing_e2e400User has no existing E2E keys. Use bootstrap/complete for first device setup.
no_face422No usable face detected in the selfie
no_images_provided400At least one image (front or back) is required
no_reusable_record400No reusable verification found — please verify fully.
no_verification404This app has no verification set up yet. Open Verification in the dev console once to provision it.
not_found404User not found
not_linked400Sign in with Valyd before reusing your identity.
otp_expired410This OTP has expired
otp_invalid400Invalid OTP
otp_not_found404Invalid OTP
pairing_already_exchanged409Tokens have already been issued for this pairing
pairing_already_fulfilled409This pairing request has already been fulfilled
pairing_expired410Pairing request has expired
pairing_incomplete400Pairing request is missing Device B public key. Device B must provide its public key first.
pairing_not_found404Pairing request not found
pairing_not_fulfilled400Pairing is not yet complete. Status:
portrait_invalid
portrait_not_found
rate_limited429Back off and retry after the window resets.
recovery_phrases_not_set404Recovery phrases not set for this user
registration_failed500Registration failed. Please try again.
required_face_checks_incomplete409Approval requires passed ID verification, liveness, and face match checks.
requires_login401User must authenticate first
reuse_not_available400Your Valyd account is no longer verified — please complete the full verification.
review_not_pending409Only an IN_REVIEW session can be manually decided.
sdk_compare_failed
server_error500Unexpected error
session_closed409This verification session is already closed.
session_expired410Verification session has expired
session_not_foundWrong or expired session id.
sso_error500Sign-in failed. Please try again.
sso_exchange_failed401Could not complete sign-in with Valyd.
sso_no_identity422Valyd did not return any account identity.
sso_not_configured503Valyd SSO is not configured on this server.
stored_reference_invalid
stored_reference_invalid_type
tamper_detected409payload_hash does not match the server-signed attestation
token_error500Could not issue tokens
token_issuance_failed500Token issuance failed
token_missing401Session token is required.
too_many_attempts429Too many failed face checks
too_many_frames400At most 8 frames are accepted.
tracking_already_used403Tracking ID has already been used
tracking_expired403Tracking ID has expired
tracking_not_found404Tracking ID not found or invalid
unauthenticated401Account not found.
unauthorized401, 403Not authorized.
unauthorized_client403This app is not active.
unauthorized_domain403Unauthorized domain
unknown_band
unsupported_grant_type400only authorization_code supported
unsupported_response_type400Only response_type=code is supported
user_deleted410This device was linked to a deleted account. Please clear your local data and register again.
user_has_no_face_reference
user_not_found400, 404User not found
userinfo_failed
valyd_account_mismatch403This verification belongs to a different Valyd account. Sign in as that account to continue.
valyd_login_required401Sign in to your Valyd account to continue this verification.
verification_soft_locked423Verification is temporarily locked. Please contact support.
wc_error400WC API error
workflow_not_found404The workflow id does not belong to this project — copy it from the portal.
wrapped_ku_recovery_not_set404WrappedKuRecovery not set for this user
wrong_endpoint400This endpoint expects image IDs, not file uploads. Use the file upload endpoint instead.

4. Troubleshooting the common integration mistakes

State mismatch on the callback. The state on your callback must equal the one you stored before redirecting (the button stores it in the valyd_oidc_state cookie; the SDK transaction carries it). If it differs, the login is forged or expired — restart the flow. Never skip this check.

invalid_grant on token exchange. Authorization codes are single-use and expire in ~2 minutes, and are bound to your client and redirect_uri. Exchange immediately, exactly once, with the same redirect_uri you authorized with.

Redirect URI mismatch. URIs are matched exactly — scheme, host, port, and path. Register every environment’s callback in the Developer Portal.

insufficient_scope on userinfo. OIDC resource calls require the openid scope in the token. The SDK and button add it automatically; raw integrations must include it in scope.

Wrong environment host. Each environment has its own IdP host (this documentation’s is idp.valyd.work). A token from one environment never works on another — and the Sign-in button targets whichever host served its script.

Refresh suddenly failing. Refresh tokens rotate on every use. If you replay an old one, every refresh token for that user+client is revoked (theft protection) — persist the newest token atomically, then re-login once.

Last updated on