Error codes
Failures return application/problem+json with code, a finer-grained reason, a short human detail (never raw tool output), and hint. Legacy error mirrors detail (or a stable title for 404). Branch on reason, falling back to code.
| code | HTTP | Meaning |
|---|---|---|
| bad_request | 400 | Invalid parameters or multipart body |
| invalid_document | 400 | PDF could not be parsed |
| unauthorized | 401 | Missing or invalid credentials |
| forbidden | 403 | Plan or permission denied |
| not_found | 404 | Unknown operation path |
| rate_limited | 429 | Quota exhausted — wait and retry |
| unavailable | 503 | Optional dependency missing |
| missing_dependency | 503 | External binary not installed |
| internal | 500 | Unexpected server failure |
Reasons
| reason | HTTP | Meaning |
|---|---|---|
| invalid_pdf | 400 | Not a PDF, or damaged beyond repair (try Repair PDF) |
| password_required | 400 | Encrypted input and no password given |
| wrong_password | 400 | The password does not open this PDF |
| page_out_of_range | 400 | A requested page does not exist |
| invalid_page_selection | 400 | Page list syntax is invalid (use 1,3,5-8, 7-, all or 2n) |
| invalid_parameter | 400 | Another field is invalid; detail names the field |
| unsupported_file_type | 400 | The operation does not accept this input type |
| url_not_allowed | 400 | URL is not a public http(s) address |
| upload_incomplete | 400 | Chunked upload completed with chunks missing |
| payload_too_large | 413 | Body over the single-request limit: use chunked uploads |
| url_fetch_failed | 422 | The web page could not be loaded |
| upload_not_found | 404 | Unknown, expired or already used upload id |
| upload_limit_reached | 429 | Too many uploads in progress; retry later |
| insufficient_storage | 507 | Server upload storage is full; retry later |
Other failures use the code value as their reason (rate_limited, missing_dependency, unavailable, internal, ...).
No content (204)
Two answers are not errors but have nothing to return: the table extractors (convert/pdf/csv, convert/pdf/xlsx) reply 204 when a PDF has no detectable table. The pages need a real text layer and at least two columns of aligned data; a scan without OCR, or ordinary prose, yields nothing.
The SDK, CLI and MCP server treat a 204 as a failure with code = no_content so callers never mistake it for a successful 0-byte extraction; the website says the same in plain language. Branch on code === "no_content" if an empty result is acceptable to you.
Client-side codes
Some failures never reach the server, so there is no problem+json body to read. The SDK throws Pdf123Error with one of these code values instead, and the CLI and MCP server print or return it:
| code | Meaning |
|---|---|
| no_content | The call worked but there is nothing to return (see the 204 section above) |
| timeout | The request exceeded timeoutMs (default 5 minutes) |
| cancelled | Your own AbortSignal aborted the call |
| network_error | The request never got an answer: DNS, TLS, or a dropped connection |
| bad_response | An answer arrived that could not be parsed as the promised type |
| input_unreadable | A local path could not be read (SDK/CLI/MCP only, before anything is uploaded) |
The CLI writes reason:, code: and hint: lines to stderr next to the message, and the MCP server appends the same as Reason:, Code: and Hint:, so a caller can branch without matching prose.
Files over 100 MB
A single request is capped at 100 MB. Upload bigger files (up to 500 MB) in chunks, then pass the id to any operation as <field>@upload, e.g. fileInput@upload=<id>:
POST /api/v1/uploadswith JSON{filename, size, contentType}→{id, chunkSize, chunkCount, maxBytes, expiresAt}PUT /api/v1/uploads/{id}/chunks/{index}with eachchunkSizeslice (0-based, any order; the last one is the remainder)POST /api/v1/uploads/{id}/complete, then call the operation. An upload is removed after the first successful operation and expires after an hour;DELETE /api/v1/uploads/{id}aborts it.
GET /api/v1/info/status reports maxUploadBytes, maxChunkedUploadBytes and uploadChunkBytes. The TypeScript SDK and the pdfx CLI switch to chunked uploads automatically.
OpenAPI: /v1/openapi.json