Send invoices in. Get data out. No downloads.
Send a PDF to your ConvertPDF.pro API address from Make, Zapier, n8n or your own code, and get clean JSON back — or have the result pushed to your system by webhook. Each PDF page uses one page from your pack, exactly like the web app. No subscription.
Your API access
Checking your account…
Quick start
Store your key in an environment variable first (export CONVERTPDF_API_KEY=…), then send an invoice:
printf '{"template":"invoice","pdfBase64":"%s"}' "$(base64 < invoice.pdf | tr -d '\n')" > request.json
curl -s https://convertpdf.pro/api/v1-extract \
-H "Authorization: Bearer $CONVERTPDF_API_KEY" \
-H "Content-Type: application/json" \
-d @request.jsonYou get back one JSON object. Values are under “data”:
{
"ok": true,
"document": { "name": "document.pdf", "pageCount": 1 },
"extracted_at": "2026-10-09T21:15:00.000Z",
"model": "claude-sonnet-5",
"data": {
"vendor": "Northline Supply",
"invoice_number": "INV-20458",
"invoice_date": "2026-03-14",
"total": 156.5,
"line_items": [
{ "description": "Widget", "quantity": 4, "unit_price": 30, "amount": 120 },
{ "description": "Fastener kit", "quantity": 2, "unit_price": 18.25, "amount": 36.5 }
]
},
"details": { "vendor": { "label": "Vendor", "value": "Northline Supply", "status": "extracted" }, "...": "..." },
"needs_review": false,
"review_fields": [],
"remaining_pages": 98,
"charged": true,
"read_method": "text_layer",
"webhook": { "delivered": true, "attempts": 1, "status": 200, "error": null }
}needs_review turns true when a value could not be confirmed or a required value (vendor, invoice number, total) is empty. review_fields says which ones, so your automation can route only those to a person.
Connect it to your tools
We have not published native Zapier or Make apps yet. Use their generic web-request step instead:
- Make: the HTTP module (“Make a request”). Method POST, header
Authorization: Bearer your key, body type raw JSON. - Zapier: Webhooks by Zapier, “Custom Request”, method POST (availability depends on your Zapier plan).
- n8n: the HTTP Request node, with the Extract From File node (operation “Move File to Base64 String”) in front of it.
- Your own code: any language that can send an HTTPS POST.
The PDF has to be sent as base64 text in pdfBase64, so add a step that converts the file to base64 first. For a photo or scan saved as an image, send it the same way in imageBase64 instead (send one or the other, not both).
Webhooks: push the result to your system
Add a webhookUrl and we also POST the result to it, signed so you can verify it.
{
"template": "invoice",
"pdfBase64": "<the PDF as base64 text>",
"webhookUrl": "https://hook.example.com/your-endpoint"
}The webhook receives the same JSON as the response above (without the "webhook" field), plus "event": "extraction.completed".
- The URL must be https on a public hostname (no IP addresses, no internal or local addresses).
- Headers sent:
X-ConvertPDF-Signature,X-ConvertPDF-Timestamp,X-ConvertPDF-Delivery-Id(the same id on a retry, so you can ignore duplicates). - If your endpoint answers with a server error (5xx), “too many requests” (429), a network error or does not answer within 6 seconds, we try once more after a second. Other error codes are not retried. The outcome is shown in the
webhookfield of the response, and a failed delivery never costs you extra pages. - Most digital PDFs finish within a few seconds to half a minute. Scans take longer because they are read first, and in the worst case one request can run for close to four minutes. Set your tool’s timeout as high as it allows (at least 240 seconds). Your hosting limits may cut a request short before that, so test with a real scan before relying on it. A webhook is sent from inside the same request, so it does not help if your tool gives up early, and there is no background mode yet. If your tool cannot wait that long, scans may not suit it yet. A request that your tool abandoned may still be completed and charged.
- Checking the signature is optional but recommended for anything that writes to your books. It needs the raw request body, which some no-code “catch hook” steps do not expose; the example below is for your own code.
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody must be the exact request body text, before any JSON parsing.
function isValid(rawBody, headers, webhookSecret) {
const timestamp = Number(headers["x-convertpdf-timestamp"]);
const signature = headers["x-convertpdf-signature"] ?? "";
if (!Number.isFinite(timestamp) || Math.abs(Date.now() / 1000 - timestamp) > 300) return false; // missing or too old
const expected =
"sha256=" + createHmac("sha256", webhookSecret).update(timestamp + "." + rawBody).digest("hex");
return signature.length === expected.length &&
timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}Errors
401 missing_api_key / invalid_api_keyNo key, or the key is not valid (for example it was rotated). Use the API key from this page, not your web-app login.402 insufficient_pagesYour pack has fewer pages left than this PDF has.400 invalid_pdfNot a readable PDF, or password-protected or damaged.400 invalid_imageimageBase64 is not a JPEG, PNG or WebP image.422 scan_unreadableNo readable text could be found in the scan. Try a sharper, upright image.413 scan_too_many_pagesScanned documents are limited to 10 pages.400 ambiguous_inputSend exactly one of pdfBase64 or imageBase64, not both.409 duplicate_in_progressThe same document is already being processed on your account. Wait for it to finish (or a few minutes), then retry. This request was not charged.429 scan_in_progressAnother scan from your account is still being read. Scans are read one at a time per account; wait for it to finish, then retry.429 rate_limitedThe AI service is busy. Retry shortly.400 too_many_pagesMore than 20 pages.400 invalid_templateThe template is not “invoice” or a valid custom template.400 invalid_webhook_urlThe webhook URL is not an https URL on a public hostname.413The PDF has too much text (over about 50,000 characters).503 provider_timeoutThe extraction took too long. No pages are charged; try again.Limits
- Scanned PDFs and photos (JPEG, PNG, WebP) work too, up to 10 pages, and are read by AI before extraction. The result includes
"read_method": "ai_vision". Scans are less exact than digital PDFs, so rely on the needs_review flag. A PDF that has any scanned page is read entirely as a scan (10-page limit), and the file itself is sent to the AI provider. - Up to 20 pages, about 3 MB and about 50,000 characters of text per PDF.
- Paid page packs only; pages are deducted exactly like the web app.
- If nothing at all is found in a document (every field empty), it is not charged and the response shows
"charged": false. This applies to up to 5 such results per day per account; after that they are charged like any other document. - The first time the same document text is sent again, it is a free redo instead of being charged again. It is applied automatically, so an automatic retry in your tool can use it up; later repeats are charged. Scans are read by AI each time, so their text is rarely identical and they rarely qualify.
- Send the PDF itself — we do not fetch PDFs from links.
Privacy: unlike the in-browser converter, the API receives your PDF on our server so it can read the text. The extracted text is then sent securely to an AI provider to find the fields. We do not intentionally store that document text afterward, and we do not guarantee how long the AI provider itself retains it. For scans and photos, the file itself is sent to the AI provider so it can be read.