{"openapi":"3.0.3","info":{"title":"PDF Vision API","version":"1.0.0","description":"Transform PDF files from your own backend: compress, merge, split and watermark.\n\nEvery operation is a single call — you send a file, you get the file back. Nothing is stored:\nuploads live in a temporary directory that is deleted once the response is written.\n\nAuthenticate with an API key created from your developer dashboard. Keys are secrets meant for\nserver-to-server use: never ship one in a browser, a mobile app or any client you do not control.","contact":{"name":"PDF Vision","url":"https://pdf-vision.com/developers"}},"servers":[{"url":"https://api.pdf-vision.com","description":"Production"},{"url":"http://localhost:8081","description":"Local development"}],"tags":[{"name":"Transform","description":"Operations that take a PDF and return a PDF."},{"name":"Secure","description":"Passwords, restrictions and redaction."},{"name":"Convert","description":"Between PDF and Office formats. Two of these are billed per call."},{"name":"Read","description":"Getting text out of documents that do not have any."},{"name":"AI","description":"Reading, answering and translating. Sends text to a third-party model; needs a paid plan."},{"name":"Account","description":"What the key is allowed to do, and what is left of today."}],"security":[{"apiKeyAuth":[]},{"bearerAuth":[]}],"paths":{"/v1/me":{"get":{"tags":["Account"],"operationId":"getAccount","summary":"Check a key and see the remaining allowance","description":"Consumes nothing. Use it to verify a key at startup rather than spending a document to find out it is invalid.","responses":{"200":{"description":"The key is valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/v1/compress":{"post":{"tags":["Transform"],"operationId":"compress","summary":"Make a PDF smaller","description":"Colours are preserved at every quality level. `strong` downsamples images to 72 dpi; `light` keeps 150 dpi.\n\nThe result is **never larger than what you sent**: a document with nothing to compress\n(text only, no images) comes back unchanged rather than inflated.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The PDF to compress."},"quality":{"type":"string","enum":["light","balanced","strong"],"default":"balanced"}}}}}},"responses":{"200":{"$ref":"#/components/responses/PdfFile"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/merge":{"post":{"tags":["Transform"],"operationId":"merge","summary":"Join several PDFs into one","description":"Pages appear in the order the files are sent. Between 2 and 20 files.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["files"],"properties":{"files":{"type":"array","minItems":2,"maxItems":20,"items":{"type":"string","format":"binary"}},"filename":{"type":"string","description":"Name of the returned file, without extension.","default":"merged"}}}}}},"responses":{"200":{"$ref":"#/components/responses/PdfFile"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/split":{"post":{"tags":["Transform"],"operationId":"split","summary":"Split a PDF","description":"The mode decides what comes back, so you know before calling:\n\n- `extract` (with `from`/`to`) returns **one PDF** — `application/pdf`.\n- `ranges` (e.g. `1-3,7,10-12`) returns **one PDF per range** — `application/zip`.\n- `pages` (default) returns **one PDF per page** — `application/zip`.\n\nAn invalid range is rejected rather than skipped: a partial archive that looks complete is worse than an error.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"},"mode":{"type":"string","enum":["pages","ranges","extract"],"default":"pages"},"ranges":{"type":"string","description":"Required when `mode=ranges`. Example: `1-3,7,10-12`.","example":"1-3,7,10-12"},"from":{"type":"integer","minimum":1,"description":"Required when `mode=extract`. First page, 1-based."},"to":{"type":"integer","minimum":1,"description":"Last page when `mode=extract`. Defaults to `from`."}}}}}},"responses":{"200":{"description":"One PDF, or a ZIP archive when the mode produces several files.","headers":{"Content-Disposition":{"schema":{"type":"string"},"description":"Suggested filename."}},"content":{"application/pdf":{"schema":{"type":"string","format":"binary"}},"application/zip":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/watermark":{"post":{"tags":["Transform"],"operationId":"watermark","summary":"Stamp text diagonally across every page","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","text"],"properties":{"file":{"type":"string","format":"binary"},"text":{"type":"string","example":"CONFIDENTIAL"},"font_size":{"type":"number","minimum":10,"maximum":300,"default":60},"font_family":{"type":"string","enum":["Helvetica","Helvetica-Bold","Times-Roman","Times-Bold","Courier","Courier-Bold"],"default":"Helvetica"},"color":{"type":"string","example":"#FF0000","default":"#000000"},"opacity":{"type":"number","minimum":0,"maximum":1,"default":0.3}}}}}},"responses":{"200":{"$ref":"#/components/responses/PdfFile"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/protect":{"post":{"tags":["Secure"],"operationId":"protect","summary":"Encrypt a PDF with a password","description":"AES encryption at 128 or 256 bits. 40-bit RC4 is deliberately not offered: it breaks in seconds\non an ordinary machine, and an API should not let you pick a decorative protection by accident.\n\nDigital signatures are not part of this endpoint.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","password"],"properties":{"file":{"type":"string","format":"binary"},"password":{"type":"string","description":"The password that will open the document."},"owner_password":{"type":"string","description":"Password that lifts the permissions below. Defaults to `password`."},"key_length":{"type":"integer","enum":[128,256],"default":256},"permissions":{"type":"string","description":"Comma-separated list of what remains ALLOWED: `printing`, `modifying`, `copying`, `annotating`, `filling_forms`. Anything not listed is denied. Omit to deny nothing.","example":"printing,copying"}}}}}},"responses":{"200":{"$ref":"#/components/responses/PdfFile"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/unlock":{"post":{"tags":["Secure"],"operationId":"unlock","summary":"Remove a password from a PDF","description":"The password is **required**, and that is the whole reason this endpoint can exist: you prove\nthat the document already opens for you. A wrong password returns `wrong_password`, which is\ndistinct from a failure — ask the user again rather than retrying the same call.\n\nTo lift printing or copying restrictions on a document that opens without a password, use\n`/v1/remove-restrictions` instead.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","password"],"properties":{"file":{"type":"string","format":"binary"},"password":{"type":"string","description":"The password that opens the document."}}}}}},"responses":{"200":{"$ref":"#/components/responses/PdfFile"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/remove-restrictions":{"post":{"tags":["Secure"],"operationId":"removeRestrictions","summary":"Lift printing, copying and editing restrictions","description":"No password is asked for, and that is not an oversight: owner restrictions are advisory in the\nPDF format — the document is not encrypted for the reader, it merely asks to be obeyed.\n\nThis does not unlock anything. On a document that asks for a password to open, it fails; use\n`/v1/unlock`. Call `/v1/inspect` first if you do not know which one you have.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"$ref":"#/components/responses/PdfFile"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/redact":{"post":{"tags":["Secure"],"operationId":"redact","summary":"Permanently remove text from a PDF","description":"Removes the text objects themselves, not a black rectangle drawn over them: a rectangle moves,\nand the text underneath still copies.\n\nIf nothing matches, the call **fails** with `nothing_redacted` (422) rather than returning the\nuntouched document. A file named `_redacted` that still contains the secret is worse than no file.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","text"],"properties":{"file":{"type":"string","format":"binary"},"text":{"type":"string","description":"The text to remove.","example":"Jane Doe"},"case_sensitive":{"type":"boolean","default":false},"whole_word":{"type":"boolean","default":false},"color":{"type":"string","enum":["black","white"],"default":"black"}}}}}},"responses":{"200":{"$ref":"#/components/responses/PdfFile"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/inspect":{"post":{"tags":["Secure"],"operationId":"inspect","summary":"Report what a PDF allows, before acting on it","description":"The only operation that returns a verdict instead of a file. Call it when you do not know whether a document needs `/v1/unlock` or `/v1/remove-restrictions`; `suggested_operation` says which.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"},"password":{"type":"string","description":"Optional. When given, the report says whether it opens the document."}}}}}},"responses":{"200":{"description":"What the document allows.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Inspection"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/word-to-pdf":{"post":{"tags":["Convert"],"operationId":"wordToPdf","summary":"Render a Word document as PDF","description":"Runs on our own machines. `PV-Warnings: LIMITED_FIDELITY` means the high-fidelity path was unavailable and a fallback produced the file — the text is right, the layout may not be.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":".doc or .docx"}}}}}},"responses":{"200":{"$ref":"#/components/responses/PdfFile"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/excel-to-pdf":{"post":{"tags":["Convert"],"operationId":"excelToPdf","summary":"Render a spreadsheet as PDF","description":"Runs on our own machines. Page setup in the workbook is preserved unless you override it below.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":".xls, .xlsx, .xlsm or .csv"},"layout":{"type":"string","enum":["preserve","fit-width","fit-page"],"default":"preserve"},"orientation":{"type":"string","enum":["preserve","portrait","landscape"],"default":"preserve"},"paper_size":{"type":"string","enum":["preserve","A4","Letter"],"default":"preserve"},"sheets":{"type":"string","enum":["all","active"],"default":"all"}}}}}},"responses":{"200":{"$ref":"#/components/responses/PdfFile"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/pdf-to-markdown":{"post":{"tags":["Convert"],"operationId":"pdfToMarkdown","summary":"Extract a PDF as structured Markdown","description":"Runs on our own machines. Headings are inferred from character size and weight.\n\nA document with **no text layer** — an image or a scan — is refused with `no_text_layer` (422)\nrather than returned as an empty file: the conversion is not what is missing, OCR is.\n`PV-Warnings` may carry `SCANNED`, `TABLES_AS_TEXT` or `TRUNCATED_AT_<n>`.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"},"max_pages":{"type":"integer","minimum":1,"maximum":300,"default":300}}}}}},"responses":{"200":{"description":"The document as Markdown.","headers":{"Content-Disposition":{"schema":{"type":"string"}},"PV-Warnings":{"schema":{"type":"string"},"description":"Comma-separated. Present only when something is worth knowing."}},"content":{"text/markdown":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/pdf-to-word":{"post":{"tags":["Convert"],"operationId":"pdfToWord","summary":"Convert a PDF into an editable Word document","description":"**This operation is billed to us per call by an external provider.** Its daily allowance is\ntherefore much smaller than the rest of the API — budget for it before you write a loop.\nCall `/v1/me` to see what is left.\n\nIf the provider is unreachable you get `service_unavailable` (503), not a generic failure.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"The document as .docx.","headers":{"Content-Disposition":{"schema":{"type":"string"}}},"content":{"application/vnd.openxmlformats-officedocument.wordprocessingml.document":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/v1/pdf-to-excel":{"post":{"tags":["Convert"],"operationId":"pdfToExcel","summary":"Convert the tables in a PDF into a spreadsheet","description":"**Billed to us per call by an external provider**, like `/v1/pdf-to-word`: the same much smaller daily allowance applies.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"},"mode":{"type":"string","enum":["table","text"],"default":"table","description":"`table` detects grids; `text` lays the text out cell by cell."}}}}}},"responses":{"200":{"description":"The tables as .xlsx.","headers":{"Content-Disposition":{"schema":{"type":"string"}}},"content":{"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Unavailable"}}}},"/v1/ocr":{"post":{"tags":["Read"],"operationId":"ocr","summary":"Make a scanned PDF searchable","description":"Adds a text layer to pages that are only images, and returns the same document, searchable.\n\nBy default **pages that already contain text are left untouched**. `force=true` rasterises every\npage and replaces existing text with what OCR reads — use it only when you know the existing\ntext layer is wrong.\n\nAn unavailable language is **refused**, never quietly replaced by English: OCR in the wrong\nlanguage returns plausible-looking nonsense that is very hard to notice.\n\nAt most 100 pages per call. Longer documents are refused with `too_many_pages` — split them with\n`/v1/split` and send the parts. Expect roughly two seconds per page.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"},"language":{"type":"string","enum":["eng","fra","deu","spa","ita","por","rus","ara","chi_sim","jpn"],"default":"eng","description":"ISO 639-3. The document language, not yours."},"force":{"type":"boolean","default":false,"description":"Re-OCR pages that already have text, replacing it."}}}}}},"responses":{"200":{"$ref":"#/components/responses/PdfFile"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/summarize":{"post":{"tags":["AI"],"operationId":"summarize","summary":"Summarise a document","description":"**This operation sends the document text to a third-party model provider** to be processed. It is not\nretained by them to train models, and nothing is stored on our side. See section 13 of the terms.\n\n**Requires a paid plan.** On a free account the allowance is zero and the call returns `plan_required`\n(403), not `quota_exceeded` — waiting until tomorrow will not help.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"},"style":{"type":"string","enum":["concise","detailed","bullet-points"],"default":"concise"}}}}}},"responses":{"200":{"description":"The summary.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Summary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/ask":{"post":{"tags":["AI"],"operationId":"ask","summary":"Ask a question about a document","description":"Returns the answer **with its citations**: which page each claim came from. An answer with no\ncitation is an answer you should check.\n\nThere is no session here — every call sends the whole document — so each one costs a document,\nnot a follow-up question.\n\n**This operation sends the document text to a third-party model provider** to be processed. It is not\nretained by them to train models, and nothing is stored on our side. See section 13 of the terms.\n\n**Requires a paid plan.** On a free account the allowance is zero and the call returns `plan_required`\n(403), not `quota_exceeded` — waiting until tomorrow will not help.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","question"],"properties":{"file":{"type":"string","format":"binary"},"question":{"type":"string","maxLength":2000,"example":"What is the termination notice period?"}}}}}},"responses":{"200":{"description":"The answer and where it came from.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Answer"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/extract":{"post":{"tags":["AI"],"operationId":"extract","summary":"Pull named values out of a document","description":"Give the fields you need — `invoice number,total,due date` — and get them back. Omit `fields`\nand you get the key topics, entities and conclusions instead.\n\nThe result is **text, not guaranteed JSON**. Presenting it as a typed object would misrepresent\nwhat the model actually returned; parse it yourself, and check it.\n\n**This operation sends the document text to a third-party model provider** to be processed. It is not\nretained by them to train models, and nothing is stored on our side. See section 13 of the terms.\n\n**Requires a paid plan.** On a free account the allowance is zero and the call returns `plan_required`\n(403), not `quota_exceeded` — waiting until tomorrow will not help.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"},"fields":{"type":"string","description":"Comma-separated, at most 25.","example":"invoice number,total,due date"}}}}}},"responses":{"200":{"description":"What was found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Extraction"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/translate":{"post":{"tags":["AI"],"operationId":"translate","summary":"Translate a document, keeping its layout","description":"Returns a **PDF**, not text: same pages, same images, translated words.\n\nRight-to-left scripts are not shaped correctly — Arabic and Hebrew come out readable but badly\nlaid out. That is a known limit, said here rather than discovered on a document already sent to\na client.\n\n**This operation sends the document text to a third-party model provider** to be processed. It is not\nretained by them to train models, and nothing is stored on our side. See section 13 of the terms.\n\n**Requires a paid plan.** On a free account the allowance is zero and the call returns `plan_required`\n(403), not `quota_exceeded` — waiting until tomorrow will not help.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","target_language"],"properties":{"file":{"type":"string","format":"binary"},"target_language":{"type":"string","example":"French"},"source_language":{"type":"string","default":"auto"}}}}}},"responses":{"200":{"$ref":"#/components/responses/PdfFile"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/TooLarge"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"securitySchemes":{"apiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Your API key, e.g. `pv_live_…`. Each key carries scopes (`transform`, `secure`, `convert`, `read`, `ai`)."},"bearerAuth":{"type":"http","scheme":"bearer","description":"The same key, sent as `Authorization: Bearer pv_live_…`."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"A stable machine-readable identifier. Branch on this, never on the message.","enum":["missing_api_key","invalid_api_key","revoked_api_key","insufficient_scope","missing_file","unsupported_file_type","unexpected_field","too_many_files","invalid_parameter","password_required","wrong_password","nothing_redacted","no_text_layer","too_many_pages","plan_required","invalid_request","file_too_large","quota_exceeded","rate_limit_exceeded","operation_failed","service_unavailable"]},"message":{"type":"string","description":"A sentence meant for a developer, not an end user."},"limit":{"type":"integer"},"limit_mb":{"type":"integer"},"plan":{"type":"string"},"reset_at":{"type":"string","format":"date-time"},"required_scope":{"type":"string"}}}}},"Inspection":{"type":"object","properties":{"encrypted":{"type":"boolean","description":"The document carries an encryption dictionary."},"needs_password":{"type":"boolean","description":"A password is required to open it at all."},"password_valid":{"type":"boolean","nullable":true,"description":"Whether the password you sent opens it. `null` when you sent none."},"page_count":{"type":"integer","nullable":true},"size_bytes":{"type":"integer"},"suggested_operation":{"type":"string","enum":["unlock","remove-restrictions"],"description":"Which endpoint to call next."}}},"Summary":{"type":"object","properties":{"summary":{"type":"string"},"style":{"type":"string"},"pages":{"type":"integer","description":"Pages actually read."}}},"Answer":{"type":"object","properties":{"answer":{"type":"string"},"citations":{"type":"array","description":"Where the answer came from. An empty list means nothing was cited — check it.","items":{"type":"object","properties":{"page":{"type":"integer","nullable":true},"text":{"type":"string","nullable":true}}}},"model":{"type":"string","nullable":true}}},"Extraction":{"type":"object","properties":{"extracted":{"type":"string","description":"Text, not guaranteed JSON. Parse and check it."},"fields":{"type":"array","nullable":true,"items":{"type":"string"}}}},"Account":{"type":"object","properties":{"key":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string","example":"pv_live_A1b2C3…"},"scopes":{"type":"array","items":{"type":"string"},"example":["transform"]}}},"plan":{"type":"string","enum":["free","premium","gold"]},"max_file_size_bytes":{"type":"integer","description":"Between 100 and 300 MB depending on the plan."},"daily_allowance":{"type":"integer","nullable":true,"description":"`null` when unlimited."},"remaining_today":{"type":"integer","nullable":true,"description":"`null` when unlimited."}}}},"responses":{"PdfFile":{"description":"The resulting PDF.","headers":{"Content-Disposition":{"schema":{"type":"string"},"description":"Suggested filename."},"PV-Quota-Remaining":{"schema":{"type":"integer"},"description":"Documents left today for this operation. Absent on unlimited plans."},"PV-Quota-Reset":{"schema":{"type":"string","format":"date-time"}}},"content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"BadRequest":{"description":"Something in the request is wrong and retrying it unchanged will fail again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing, invalid or revoked API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The key is valid but lacks the scope for this operation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"TooLarge":{"description":"The file is larger than the plan allows.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unprocessable":{"description":"The file was received but could not be processed — damaged or password-protected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unavailable":{"description":"An external provider this operation depends on is unreachable. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Daily allowance reached (`quota_exceeded`) or too many requests per minute (`rate_limit_exceeded`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}