Get started
Errors and retries
Error format, every status code and message, and when to retry a HireLayer API call.
Successful calls return 2xx. Every error returns a non-2xx status and a JSON body with an error string. Branch on the HTTP status first.
{
"error": "This document does not appear to be a CV or resume. Please upload a CV or resume and try again.",
"code": "DOCUMENT_NOT_A_RESUME"
}{
"success": false,
"error": "job_text cannot be empty"
}erroris always present and human-readable. Every exact message is listed in the catalogue below.codeis present on CV Extract errors:INVALID_FILE,DOCUMENT_NOT_A_RESUME,DOCUMENT_TEXT_EMPTY,DOCUMENT_UNREADABLE,DOCUMENT_TOO_LARGE,PARSER_UNAVAILABLE.- CV Extract errors also carry an
x-parser-request-idheader. Log it.
| Status | Meaning | Action |
|---|---|---|
400 | Invalid request: missing field, wrong type, limit exceeded. | Fix the request. Do not retry. |
401 | Missing or invalid API key. | Fix the key. Do not retry. |
403 | No credit left. | Add credits or upgrade, then retry. |
404 | Unknown path or wrong method. | Check the endpoint. |
413 | Upload too large (CV Extract). | Send a smaller file. |
415 | Wrong Content-Type (CV Extract). | Send multipart/form-data. |
422 | The document cannot be parsed as a resume (CV Extract). | Do not retry the same file. |
500 | Invalid JSON body, or an unexpected failure. | Check the body, then retry with backoff. |
502 503 504 | Temporary failure or timeout. | Retry with backoff; honour Retry-After. |
- Retry
5xxresponses and connection failures, at most 3 times, with exponential backoff and jitter (about 1 s, 2 s, 4 s). - When a
Retry-Afterheader is present, wait that many seconds. - Never retry
4xxunchanged.403can succeed once credits are added. - Failed calls consume no credit. There is no idempotency key: a call your client abandons can still complete and be charged, so keep client timeouts above the gateway timeouts (150 s for CV Extract, 65 s otherwise).
# hirelayer.py — minimal client with retries. Requires: pip install requests
import mimetypes
import os
import random
import time
import requests
API_BASE = "https://onlineresumeparser.com/api"
class HireLayerError(Exception):
def __init__(self, status, message, code=None, request_id=None):
super().__init__(f"HireLayer {status}: {message}")
self.status = status
self.code = code
self.request_id = request_id
def _delay(attempt, retry_after):
if retry_after and retry_after.isdigit():
return int(retry_after)
return min(30, 2**attempt) + random.random()
def call(method, path, *, json=None, files=None, data=None, timeout=65, max_retries=3):
"""Call HireLayer. Retries 5xx and connection failures, raises HireLayerError otherwise."""
headers = {"X-API-Key": os.environ["HIRELAYER_API_KEY"]}
for attempt in range(max_retries + 1):
try:
response = requests.request(
method,
API_BASE + path,
headers=headers,
json=json,
files=files,
data=data,
timeout=timeout,
)
except requests.ConnectionError:
if attempt == max_retries:
raise
time.sleep(_delay(attempt, None))
continue
if response.ok:
return response.json()
if response.status_code >= 500 and attempt < max_retries:
time.sleep(_delay(attempt, response.headers.get("Retry-After")))
continue
try:
body = response.json()
except ValueError:
body = {}
raise HireLayerError(
response.status_code,
body.get("error", response.reason),
body.get("code"),
response.headers.get("x-parser-request-id"),
)
def parse_resume(path, application_id=None):
content_type = mimetypes.guess_type(path)[0] or "application/octet-stream"
with open(path, "rb") as file:
content = file.read() # bytes can be re-sent on retry
return call(
"POST",
"/v3/parser",
files={"file": (os.path.basename(path), content, content_type)},
data={"application_id": application_id} if application_id else None,
timeout=150,
)
// hirelayer.mts — minimal client with retries. Node.js 18+, run with tsx.
const API_BASE = 'https://onlineresumeparser.com/api'
export class HireLayerError extends Error {
status: number
code?: string
requestId?: string
constructor(status: number, message: string, code?: string, requestId?: string) {
super(`HireLayer ${status}: ${message}`)
this.status = status
this.code = code
this.requestId = requestId
}
}
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
function retryDelay(attempt: number, retryAfter: string | null) {
const seconds = Number(retryAfter)
if (retryAfter && Number.isInteger(seconds)) return seconds * 1000
return Math.min(30_000, 1000 * 2 ** attempt) + Math.random() * 1000
}
/** Calls HireLayer. Retries 5xx responses, throws HireLayerError otherwise. */
export async function callHireLayer<T>(
path: string,
options: { json?: unknown; form?: FormData; timeoutMs?: number } = {},
maxRetries = 3
): Promise<T> {
const headers: Record<string, string> = {
'X-API-Key': process.env.HIRELAYER_API_KEY!,
}
let body: string | FormData | undefined = options.form
if (options.json !== undefined) {
headers['Content-Type'] = 'application/json'
body = JSON.stringify(options.json)
}
for (let attempt = 0; ; attempt++) {
const response = await fetch(API_BASE + path, {
method: body === undefined ? 'GET' : 'POST',
headers,
body,
signal: AbortSignal.timeout(options.timeoutMs ?? 65_000),
})
if (response.ok) return (await response.json()) as T
if (response.status >= 500 && attempt < maxRetries) {
await sleep(retryDelay(attempt, response.headers.get('Retry-After')))
continue
}
const payload = await response.json().catch(() => ({}))
throw new HireLayerError(
response.status,
payload.error ?? response.statusText,
payload.code,
response.headers.get('x-parser-request-id') ?? undefined
)
}
}
Exact error messages, per endpoint.
POST/api/v3/parser17 errors›
- 400Missing required file field
Do not retry
- 400application_id must be a string when provided
Do not retry
- 400
INVALID_FILEThe uploaded file is empty or invalid. Please check the file and try again.Do not retry
- 401Missing API Key
Do not retry
- 401Invalid API Key
Do not retry
- 403Insufficient credits available
Fix, then retry
- 413The uploaded file is too large to process. Please upload a smaller file.
Do not retry
- 415Content-Type must be multipart/form-data
Do not retry
- 422
DOCUMENT_NOT_A_RESUMEThis document does not appear to be a CV or resume. Please upload a CV or resume and try again.Do not retry
- 422
DOCUMENT_TEXT_EMPTYThe text could not be extracted from this document. Please verify that the file is readable and contains selectable text.Do not retry
- 422
DOCUMENT_UNREADABLEThe document could not be read. Please upload a valid, readable file.Do not retry
- 422
DOCUMENT_TOO_LARGEThis document contains too much text to process. Please try a shorter or simpler version.Do not retry
- 500Internal Server Error
Retry with backoff
- 502
PARSER_UNAVAILABLEAn error occurred while processing the document or extracting its text. Please try again later.Retry with backoff
- 503
PARSER_UNAVAILABLEAn error occurred while processing the document or extracting its text. Please try again later.Retry with backoff
- 503Credit service temporarily unavailable
Retry with backoff
- 504
PARSER_UNAVAILABLEAn error occurred while processing the document or extracting its text. Please try again later.Retry with backoff
POST/api/v1/jobs/extract-criteria13 errors›
- 400Request body must be a JSON object
Do not retry
- 400The request contains unsupported fields
Do not retry
- 400The 'job_text' field is required
Do not retry
- 400job_text cannot be empty
Do not retry
- 400job_text must be 50000 characters or less
Do not retry
- 401Missing API Key
Do not retry
- 401Invalid API Key
Do not retry
- 403Insufficient credits available
Fix, then retry
- 500Internal server error
Retry with backoff
- 500Internal server error. Please try again later.
Retry with backoff
- 502Upstream API unavailable
Retry with backoff
- 502The AI processing step failed. Please try again later.
Retry with backoff
- 503Credit service temporarily unavailable
Retry with backoff
POST/api/v1/matching/job-candidate18 errors›
- 400Request body must be a JSON object
Do not retry
- 400The request contains unsupported fields
Do not retry
- 400The 'job_text' field is required
Do not retry
- 400job_text cannot be empty
Do not retry
- 400job_text must be 50000 characters or less
Do not retry
- 400The 'candidate_text' field is required
Do not retry
- 400candidate_text cannot be empty
Do not retry
- 400candidate_text must be 50000 characters or less
Do not retry
- 400The 'matching_criteria' field must be an array
Do not retry
- 400matching_criteria contains an invalid criterion
Do not retry
- 401Missing API Key
Do not retry
- 401Invalid API Key
Do not retry
- 403Insufficient credits available
Fix, then retry
- 500Internal server error
Retry with backoff
- 500Internal server error. Please try again later.
Retry with backoff
- 502Upstream API unavailable
Retry with backoff
- 502The AI processing step failed. Please try again later.
Retry with backoff
- 503Credit service temporarily unavailable
Retry with backoff
POST/api/v1/matching/job-candidates/rank19 errors›
- 400Request body must be a JSON object
Do not retry
- 400The request contains unsupported fields
Do not retry
- 400The 'job_text' field is required
Do not retry
- 400job_text cannot be empty
Do not retry
- 400job_text must be 50000 characters or less
Do not retry
- 400The 'candidates' field must be an array
Do not retry
- 400candidates cannot be empty
Do not retry
- 400candidates must contain 10 candidates or fewer
Do not retry
- 400candidates contains an invalid candidate
Do not retry
- 400candidate_text must be 50000 characters or less
Do not retry
- 400candidates contains duplicate ids
Do not retry
- 401Missing API Key
Do not retry
- 401Invalid API Key
Do not retry
- 403Insufficient credits available
Fix, then retry
- 500Internal server error
Retry with backoff
- 500Internal server error. Please try again later.
Retry with backoff
- 502Upstream API unavailable
Retry with backoff
- 502The AI processing step failed. Please try again later.
Retry with backoff
- 503Credit service temporarily unavailable
Retry with backoff
POST/api/v1/skills/match16 errors›
- 400Provide either 'skill' or 'skills', not both
Do not retry
- 400The 'skill' or 'skills' field is required
Do not retry
- 400The 'skill' field is required
Do not retry
- 400Skill cannot be empty
Do not retry
- 400The 'skills' (list) field is required
Do not retry
- 400The 'skills' field must be a non-empty list
Do not retry
- 400Maximum 100 skills per batch request
Do not retry
- 400top_k must be an integer between 1 and 50
Do not retry
- 400Request body must be a JSON object
Do not retry
- 401Missing API Key
Do not retry
- 401Invalid API Key
Do not retry
- 403Insufficient credits available
Fix, then retry
- 500Internal server error
Retry with backoff
- 500Internal server error. Please try again later.
Retry with backoff
- 502Upstream API unavailable
Retry with backoff
- 503Credit service temporarily unavailable
Retry with backoff
GET/api/v1/skills6 errors›
- 401Missing API Key
Do not retry
- 401Invalid API Key
Do not retry
- 403Insufficient credits available
Fix, then retry
- 500Internal server error
Retry with backoff
- 502Upstream API unavailable
Retry with backoff
- 503Credit service temporarily unavailable
Retry with backoff
GET/api/v1/health1 errors›
- 502Upstream API unavailable
Retry with backoff
POST/api/v2/parser6 errors›
- 400An error occurred while processing the document or extracting its text. Please try again later.
Do not retry
- 401Missing API Key
Do not retry
- 401Invalid API Key
Do not retry
- 403Insufficient credits available
Fix, then retry
- 415Content-Type must be multipart/form-data
Do not retry
- 503Credit service temporarily unavailable
Retry with backoff