In short: one endpoint takes a file and returns invoice fields as JSON: invoice number, dates, supplier, buyer, VAT ID, IBAN, BIC, net/VAT/gross amounts and currency. E-invoices (ZUGFeRD, Factur-X, XRechnung, UBL/Peppol, Swiss QR) are read from their structured data, not recognised from a picture. Scans and photos go through recognition with arithmetic and checksum checks on top.
Get an API key and startParsing is asynchronous because a scan takes a few seconds. You send the file, you get a job number, you ask for the result.
| Step | Call |
|---|---|
| 1. Send the invoice | POST /v1/parse with header X-Api-Key and the file |
| 2. Read the result | GET /v1/parse/{job_id} until the status is done |
curl -X POST https://duebuddy.work/v1/parse \
-H "X-Api-Key: YOUR_KEY" \
-F "[email protected]"
# → {"ok":true,"job_id":123,"status":"processing"}
curl https://duebuddy.work/v1/parse/123 \
-H "X-Api-Key: YOUR_KEY"
No dependencies to install. Works on a server or a laptop.
import json, pathlib, time, urllib.request, uuid
API_KEY = "YOUR_KEY"
BASE = "https://app.duebuddy.work"
def parse(path):
data = pathlib.Path(path).read_bytes()
boundary = uuid.uuid4().hex
body = (f'--{boundary}\r\n'
f'Content-Disposition: form-data; name="file"; filename="{pathlib.Path(path).name}"\r\n'
f'Content-Type: application/pdf\r\n\r\n').encode() + data + f"\r\n--{boundary}--\r\n".encode()
req = urllib.request.Request(f"{BASE}/v1/parse", data=body, method="POST",
headers={"X-Api-Key": API_KEY,
"Content-Type": f"multipart/form-data; boundary={boundary}"})
job = json.load(urllib.request.urlopen(req))["job_id"]
while True:
time.sleep(3)
r = urllib.request.Request(f"{BASE}/v1/parse/{job}", headers={"X-Api-Key": API_KEY})
out = json.load(urllib.request.urlopen(r))
if out.get("status") in ("done", "failed"):
return out
print(parse("invoice.pdf")["fields"])
{
"status": "done",
"fields": {
"invoice_no": "R0005532486",
"invoice_date": "19.01.2016",
"due_date": "22.01.2016",
"currency": "EUR",
"seller_name": "Hetzner Online GmbH",
"seller_address": "Industriestr. 25, 91710 Gunzenhausen",
"seller_vat_id": "DE812871812",
"seller_iban": "DE92760700120750007700",
"seller_bic": "DEUTDEMM760",
"buyer_name": "Usegroup Inh. Jochen Stärk",
"gross_amount": "104.00"
}
}
Fields we could not confirm stay empty and are marked. The system does not invent values: if the arithmetic does not add up or an IBAN fails its checksum, the field is flagged instead of guessed. The the same file is deduplicated by content hash and is not charged twice.
| Format | How it is read |
|---|---|
| ZUGFeRD, Factur-X, XRechnung, UBL/Peppol | Read from the embedded XML |
| Swiss QR bill, SEPA QR (GiroCode) | Read from the QR code |
| PDF with a text layer | Read from the text layer |
| Scan or photo (PDF, JPG, PNG) | Recognition plus checks |
EUR 0.07 per scanned page. You pay for recognising an image — a scan, a photo, a screenshot. Invoices that already carry their data in code (ZUGFeRD, XRechnung, UBL, FatturaPA, QR) are read free and without limit.
Minimum top-up: EUR 8 — one month of use. The first 5 scanned pages are free, no card required. Web Beta and API usage are billed separately: the Beta allowance applies to the web app, in the API the first 5 scanned pages are free. The same file is deduplicated by content hash and is never charged twice.
For reference, published prices of comparable services run from about $0.05 (Mindee) to $1.80 (Nanonets) per document. We sit in the middle and are honest that the cheapest competitor is cheaper on paper.
The key is issued in the dashboard. Sign up, pick the parsing plan, and the key appears there. Paste it into the header X-Api-Key and you are running.
If a key was ever exposed in a screenshot or a chat, ask us for a new one. We revoke the old key; we do not keep it alive alongside the new one.
It does not create invoices, does not post to accounting accounts, and does not give tax advice. It reads incoming invoices and returns the field values. What you do with them is your system's job.
Status: 5 October 2026. Questions about rate limits and larger volumes: ask before you build, so we can tell you what the current setup handles.