Affinda Resume Parser Open console

Errors and limits

The error envelope

Every error from the parse API is a flat JSON object with two keys, and sometimes a third:

{"error": "You do not have any more credits. Please contact sales@affinda.com", "code": "no_credits"}
  • error is a message that is safe to show a person. It can change without notice.
  • code is a stable machine-readable identifier. Branch on this, never on the message or on the status alone.
  • retryAfterSeconds appears when waiting is the right response. The Retry-After HTTP header carries the same number.

This envelope belongs to the parse API. The console's own endpoints, and the wider Affinda platform API at app.affinda.com, use a different and more nested error format. If you use both, do not share error-handling code between them.

Errors raised by the parser itself, rather than by the API in front of it, are relayed to you unchanged with their own status. That is why the code values below come from two families.

Status codes

Status code What happened
400 missing_file No file in the file field, no usable raw body, or a zero-byte upload. A body sent as application/x-www-form-urlencoded lands here too, because it carries no file.
400 organization_required Your account has more than one Resume Parser organization. Pass ?organization= to say which one pays.
400 invalid_request The request was malformed in some other way.
401 unauthorized Missing, unknown, expired or wrong-region API key, or an IP address your organization does not allow. See Authentication.
402 no_credits No credits left, or credits expired. Nothing is parsed and nothing is charged.
403 forbidden Multi-factor authentication is required on your account and not set up. Finish setting it up in the console.
404 organization_not_found The organization parameter names an organization that is not one of your Resume Parser organizations.
405 method_not_allowed Only POST is implemented on this path.
413 file_too_large The file is over 20 MB. Checked before the parser is called, so it costs nothing.
413 payload_too_large The parser's own size rejection. You see this only if a document gets past the first check.
415 unsupported_format The document is not a format the parser reads. See below.
422 password_protected_document The document is encrypted. Remove the password and retry.
422 unparseable_document The file was read but nothing could be extracted from it.
422 missing_file_part The parser received a multipart request with no file part.
429 rate_limited You are over the per-minute limit. See below.
429 queue_full, queue_timeout, ocr_queue_full The parser is at capacity. Wait retryAfterSeconds and retry.
500 internal_error, internal Something failed unexpectedly. The detail is recorded on our side.
502 parser_unavailable The parser could not be reached. The request is retried once on a fresh connection first. No credit is charged.
503 shutting_down The parser instance is shutting down. Retry.
504 parser_timeout, deadline The parse did not finish in time. The API waits 30 seconds and the parser applies its own 28 second deadline, so deadline is the one you usually see. No credit is charged.

Retry 429, 502, 503 and 504. Do not retry 4xx codes that describe the request itself: the same request will fail the same way.

What the parser accepts

The cloud API is deliberately lenient. If a file might hold text, it is attempted.

Accepted Notes
PDF Including scanned PDFs, which are read with OCR.
DOCX, ODT, XLSX, ODS
DOC, XLS The legacy Microsoft formats. DOC extraction is more approximate than DOCX.
RTF, HTML, SVG
Plain text UTF-8 and UTF-16.
PNG, JPEG, GIF, TIFF, BMP, WEBP Read with OCR.

Three things are rejected rather than attempted:

  • Encrypted documents, with 422 password_protected_document. Nobody can read them, including us.
  • Empty files. A zero-byte upload is answered 400 missing_file, and a file that holds no readable text at all is answered 422 unparseable_document.
  • Legacy PowerPoint (.ppt), with 415 unsupported_format.

Anything else is attempted. A file that turns out to hold no usable text still returns 200, with very little in data and a low meta.document.extractionQuality.band. Checking that band is how you tell a thin result from a good one. A self-hosted container with OCR switched off also rejects images, with 415 unsupported_format, because there is nothing to read them with.

Two limits that truncate quietly rather than failing:

  • Only the first 20 pages of a document contribute fields.
  • OCR reads the first 3 pages. When there were more, meta.ocr.truncated is true and meta.document.warnings carries ocr_truncated.

Size limit

A file may be up to 20 MB. Larger files are rejected with 413 file_too_large before the parser is called, so they cost nothing. The size is checked against the declared Content-Length, against the multipart part, and again against the bytes actually received.

Rate limits

Limit Value
Per organization 6,000 parses per minute
Per API key 6,000 parses per minute

These are an abuse floor rather than a quota: normal use does not come near them. Going over gives 429 rate_limited. If you need more, contact sales@affinda.com.

The free tool on our website at https://www.affinda.com/free-resume-parser has its own generous daily fair-use cap, per IP address. It is a tool for people, not an API to build on.

Credits

One successful parse costs one credit, however many pages the document has. A parse that fails costs nothing: the credit is charged after the parser returns, and every error path above either never reaches the parser or never charges.

New accounts start with 1,000 free credits, valid for 14 days. Credits you buy are separate and get their own expiry at purchase.

The X-Credits-Remaining response header carries your balance after the parse was charged. It is omitted if the balance could not be read, so treat its absence as "unknown" rather than "zero".

When credits run out, or when they expire, parses stop with 402 no_credits. Nothing is parsed and nothing is charged. Buy more on the console's Billing screen at /billing.

Response headers

Header On Meaning
X-Credits-Remaining Successful parses Your credit balance after this parse.
X-Parser-Capacity-State Every response How busy the parser fleet is. A steering hint.
X-Parser-Fair-Share Every response How many concurrent parses you are currently allowed, or unlimited.
X-Parser-In-Flight Every response How many parses you currently have in flight.
Retry-After Some 429s and 503s Seconds to wait before retrying.

The three X-Parser-* headers are hints for a client that wants to pace itself. They are not promises, and they can change from one response to the next.