Errors
How the SheerID API reports errors — the error response shape, HTTP status codes, recoverable vs non-recoverable errors, a reference of common error IDs, and retry guidance.
Overview
The SheerID API reports problems in two shapes, depending on the endpoint:
- Verification endpoints return an
ErrorResponsewith a machine-readableerrorIdsarray (and thecurrentStep, so you know where the verification is). Most input problems come back inside the verification step response —errorIdsis populated and you correct the input and resubmit the same step. - Program, report, conversion, and other token-protected endpoints return a simpler
SystemErrorMessage— a human-readablesystemErrorMessagestring and, when available, anerrorIdsarray.
Branch your logic on errorIds (stable and machine-readable). Treat systemErrorMessage as debugging detail — it is not written for end users.
The error response
A verification ErrorResponse looks like this:
{
"verificationId": "111111111111111111111111",
"currentStep": "error",
"errorIds": ["invalidApiToken"],
"errorDetailId": [],
"systemErrorMessage": "Provided API token is empty or invalid",
"segment": "student",
"subsegment": null
}
| Field | Description |
|---|---|
errorIds |
Array of machine-readable error IDs. Branch on these. |
errorDetailId |
Optional finer-grained detail (e.g. document/ID-check specifics such as govIdMismatch, unableToVerify). |
currentStep |
Where the verification is now. For recoverable errors this is the step to retry; error means it ended. |
systemErrorMessage |
Debugging detail. Not end-user copy. |
redirectUrl |
Present when the error directs the user elsewhere. |
consolationRewardCode |
Present when a consolation reward applies. |
HTTP status codes
| Status | Meaning |
|---|---|
200 OK |
Request succeeded. Note: a recoverable verification error still returns 200 — the problem is in errorIds on the step response, not the HTTP status. |
202 Accepted |
Async work accepted (e.g. report generation). Poll for completion. |
400 Bad Request |
Malformed request (invalidRequest, invalidField). |
401 Unauthorized |
Missing or invalid API token (invalidApiToken). Check your Authorization: Bearer header. |
403 Forbidden |
Authenticated but not permitted (unauthorizedDomain, unauthorizedIpAddress, unauthorizedRequest). |
404 Not Found |
Unknown verification or resource (noVerification, notFound). |
429 Too Many Requests |
A limit was hit. This status is overloaded across several error IDs: one is the transient API rate limit (apiRateLimitExceeded, safe to retry); the rest are per-person limits that retrying won’t fix. Branch on the errorId, not the 429 itself — see Retry and backoff for the full list. |
200) rather than as a 4xx, your integration should inspect errorIds on every response — not just the HTTP status.
429 does not always mean “rate limited, back off and retry.” Only apiRateLimitExceeded is transient. Several per-person limits also return 429 but are not retryable — verificationLimitExceeded, docReviewLimitExceeded, reverificationDailyLimitExceeded, and incorrectVerificationOverrideCodeAttemptLimitExceeded — and retrying them in a backoff loop will always fail and wastes the user’s time. Drive your retry logic off the errorId, never off the bare 429 status.
Recoverable vs non-recoverable
- Recoverable — the verification can continue. Fix the input and resubmit the same step (
currentSteptells you which). Examples:invalidBirthDate,invalidEmail,tooManyOrganizationMatches,invalidSMSCode, document-upload issues. - Non-recoverable — the verification cannot continue. Start a new verification (or handle the terminal outcome, such as consolation). Examples:
expiredVerification,verificationLimitExceeded,docReviewLimitExceeded,fraudRulesReject.
Common errors
errorId |
Recoverable | Meaning and what to do |
|---|---|---|
invalidApiToken |
No | API token missing or invalid (HTTP 401). Fix the Authorization: Bearer <token> header. |
noProgram / invalidProgram / inactiveProgram / expiredProgram |
No | The programId is unknown, malformed, or not currently active. Verify the program. |
noVerification / expiredVerification |
No | The verificationId doesn’t exist or the verification has expired. Start a new verification. |
verificationLimitExceeded |
No | The program’s per-person verification limit was reached (HTTP 429). Do not retry — the user cannot reverify under this program. |
apiRateLimitExceeded |
No | You exceeded the API rate limit (HTTP 429). Back off and retry (see Retry and backoff). |
docReviewLimitExceeded |
No | The user exhausted document-review attempts (HTTP 429); the verification failed. Do not retry — start over, or present the consolation outcome. |
reverificationDailyLimitExceeded |
No | The per-person daily reverification limit was reached (HTTP 429). Do not retry in a backoff loop — the cap resets on its daily schedule, so the user can try again later, not immediately. |
incorrectVerificationOverrideCodeAttemptLimitExceeded |
No | Too many incorrect verification-override-code attempts (HTTP 429); the override path is locked for this verification. Do not retry. |
noRemainingRewardCodes |
No | The reward-code pool is empty. Upload more codes — see Offer Codes. |
fraudRulesReject |
No | Blocked by fraud rules. |
unauthorizedDomain / unauthorizedIpAddress / unauthorizedRequest |
No | The request isn’t permitted (domain or IP allowlist, or request context). |
internalServerError / unknownError |
No | A server-side error occurred. Retry with backoff; if it persists, contact support. |
invalidFirstName / invalidLastName / invalidEmail / invalidBirthDate / invalidPhoneNumber / invalidPostalCode |
Yes | A submitted field failed validation. Correct it and resubmit the current step. |
futureBirthDate / underagePerson / outsideAgePerson |
Yes | The birth date is in the future or outside the program’s age range. Re-collect and resubmit. |
tooManyOrganizationMatches |
Yes | The organization search was too broad. Narrow the query and resubmit. |
invalidSMSCode / expiredSMSCode |
Yes | The SMS-loop code is wrong or expired. Prompt the user to re-request and re-enter it. |
unsupportedDocMimeType / invalidFileSizeMax / invalidFileSizeEmpty / invalidNumberOfFiles |
Yes | The uploaded document violates a constraint (type, size, or count). Re-upload within the limits. |
missingRequiredMetadata |
Yes | A metadata key the program marks required was not supplied. Add it and resubmit. |
sourcesUnavailable / dataProviderError / dataNotAvailable |
Yes | A transient upstream data-source issue. Retry with backoff. |
For the complete, authoritative list of error IDs, see the ErrorId enum in the REST API reference.
Retry and backoff
Decide whether to retry from the errorId, not the HTTP status — 429 in particular is returned for both retryable and terminal conditions (see below). Retry only transient errors, using exponential backoff with jitter:
apiRateLimitExceeded(HTTP 429) — back off before retrying; respect aRetry-Afterheader if one is present.internalServerErrorand other5xxresponses — retry a few times with backoff.sourcesUnavailable,dataProviderError,dataNotAvailable— transient verification-source issues; safe to retry.
Do not retry non-recoverable business errors — the result will not change. Other terminal errors include fraudRulesReject and expiredVerification.
Every 429 and what to do
429 is the status most likely to be mis-handled, because only one of its error IDs is actually retryable. Inspect errorIds to tell them apart:
errorId |
Retry? |
|---|---|
apiRateLimitExceeded |
Yes — transient. Back off with jitter (respect Retry-After if present) and retry. |
reverificationDailyLimitExceeded |
Not now — a per-person daily cap. A backoff loop will never clear it; the user can try again after the daily window resets. |
verificationLimitExceeded |
No — terminal. The program’s per-person verification limit is reached. |
docReviewLimitExceeded |
No — terminal. Document-review attempts are exhausted. |
incorrectVerificationOverrideCodeAttemptLimitExceeded |
No — terminal. Override-code attempts are exhausted for this verification. |
Make retried calls idempotent where possible, and reuse the same verificationId rather than starting duplicate verifications.
Document-review rejections
When an uploaded document is reviewed and rejected, the verification surfaces one or more rejection reasons (the RejectionReason enum — roughly three dozen values, such as expired or unreadable documents). These are distinct from errorIds. For the full set and how to read them, see the Verification Report guide and the REST API reference.
Related
- REST API — the request/response loop these errors appear in.
- Authentication — avoid
invalidApiToken. - Offer Codes — handling
noRemainingRewardCodes.