Somewhere in a finance team's inbox is a supplier invoice with a Swiss QR bill at the bottom of it. Since Switzerland's QR-bill standard took effect, every Swiss payment slip looks like this: a QR code sitting under a printed block of IBAN, amount, and reference details, replacing the old red and orange slips entirely. It is a clean, standardized format. It is also, for whoever has to get that data into accounting software, still a QR code someone scans, reads, and retypes by hand. Standardizing the printed layout solved a printing problem. It did not solve a data-entry problem, because scanning a QR code and understanding what it means are two very different things.
That gap is where most Swiss QR bill automation attempts stall. A generic QR scanner decodes the code fine and hands back a wall of text, because a Swiss QR bill does not encode a URL or a short string the way a marketing poster does. It encodes the Swiss Payments Code: a strict, multi-line data block carrying the creditor's IBAN, the payment amount and currency, a reference number, and more, all packed into a specific line order defined by the Swiss payment standard. Read that with a generic decoder and what comes back is technically correct and practically useless, a blob of text with no keys and no structure that still needs a second parsing layer written by hand.
What the endpoint actually returns
PDF4me's Read Swiss QR Code endpoint skips that second layer entirely.
POST /api/v2/ReadSwissQRBill takes a base64-encoded PDF and decodes the embedded QR bill directly into structured payment data as a JSON object, not a raw text dump. Three fields go in: docContent (the base64 PDF), docName (the filename), and async (true for larger batches, using the standard 202-plus-polling pattern). What comes back, once decoded, is a swissQrCodeData object with the fields a finance workflow actually needs already separated: amount, currency, iban, creditorName, paymentReference, plus dueDate and purpose when the bill carries them.
{
"fileName": "invoice.pdf",
"mimeType": "application/pdf",
"fileSize": 2456789,
"success": true,
"swissQrCodeData": {
"amount": "100.00",
"currency": "CHF",
"iban": "CH9300762011623852957",
"creditorName": "Swiss Company AG",
"paymentReference": "INV-2024-001",
"dueDate": "2024-12-31",
"purpose": "Invoice payment"
}
}
That distinction matters more than it sounds like it should. PDF4me also has a general-purpose Read Barcode from PDF endpoint, and it is tempting to assume one barcode reader should handle every barcode. It will read the QR code's raw payload just fine. What it will not do is know that one block of that payload is the creditor's IBAN and another is the reference number, or that the reference needs different handling depending on whether it is a QR reference or a Creditor Reference under ISO 11649. Read Swiss QR Code exists specifically because that interpretation layer is the actual work, and it is not worth repeating by hand in every integration a team builds.
A working example
Here is the request in Python, adapted from PDF4me's official sample repository:
import os
import base64
import requests
import time
api_key = "YOUR_API_KEY" # from https://dev.pdf4me.com/dashboard/#/api-keys/
pdf_file_path = "invoice.pdf"
url = "https://api.pdf4me.com/api/v2/ReadSwissQRBill"
with open(pdf_file_path, "rb") as f:
pdf_base64 = base64.b64encode(f.read()).decode("utf-8")
payload = {
"docContent": pdf_base64,
"docName": os.path.basename(pdf_file_path),
"async": True
}
headers = {
"Authorization": f"Basic {api_key}",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
if response.status_code == 200:
print(response.json()["swissQrCodeData"])
elif response.status_code == 202:
# Async: poll the Location header until it returns 200
location_url = response.headers.get("Location")
for _ in range(20):
time.sleep(10)
poll = requests.get(location_url, headers=headers)
if poll.status_code == 200:
print(poll.json()["swissQrCodeData"])
break
else:
print(f"Error: {response.status_code} - {response.text}")
The async branch matters more here than it does for most PDF4me endpoints. Swiss QR recognition can take longer than a standard barcode read, and the official sample uses an extended 20-retry, 10-second polling loop specifically because of that, not as boilerplate copied from another endpoint.
Where this fits in an accounts payable pipeline
The realistic entry point for this endpoint is a folder, not a single file. Invoices land in a shared Dropbox, SharePoint, or email inbox, each one a PDF with a Swiss QR bill on it, arriving on no predictable schedule. Wiring Read Swiss QR Code into that intake point means every incoming invoice gets its payment data extracted automatically, at the moment it arrives, instead of sitting in a queue for someone to open and transcribe. PDF4me's own workflow write-ups show this pattern in practice: reading the creditor and reference straight out of a QR-bill PDF to auto-rename the file for filing, on Make, Zapier, and n8n, so the manual "open PDF, find the reference number, type it into the ERP" step disappears from the process rather than getting faster.
The same extracted data closes the loop the other direction too. A business that generates its own Swiss QR bills with PDF4me's Create Swiss QR Bill endpoint can verify what actually printed by reading it back with this endpoint, useful as a sanity check before a batch of invoices goes out the door. And for teams processing invoice batches that arrive as one long combined PDF rather than individual files, Split PDF by Swiss QR uses the same QR-bill boundary to break a multi-invoice batch into individual documents before extraction even starts, so the reading step operates on one invoice at a time instead of hunting for boundaries inside a combined file.
Wiring it into a no-code workflow
None of this requires custom backend code to reach production. In Make, Read Swiss QR Code is a scenario module that takes a watched file and returns the decoded payment fields directly into the scenario's data flow, ready to route into a Google Sheet, a database module, or a rename-and-file step. In Zapier, the same extraction runs as a Zap step, triggered the moment a new file lands in a watched Dropbox or Drive folder, with the creditor, IBAN, amount, and reference coming back as fields a downstream Zap step can act on without a separate parsing action. In Power Automate, it slots into a flow the same way, a natural fit for finance teams already running approval or filing flows on Microsoft's automation stack. In n8n, it becomes a node inside a self-hosted workflow a team owns end to end, useful where the extracted data needs to feed a custom or internal accounting system.
Across all four, the shape of the workflow is the same: a file appears, its payment data comes out as structured fields a few seconds later, and nobody has opened the PDF to read it themselves. Not that reading one QR bill by hand is slow, it takes seconds, but that it is one more manual step in a chain that was supposed to run without a person watching it, and every manual step in that chain is a place invoices get delayed, misfiled, or mistyped.
Seeing it before writing a line of integration code
Before wiring this into a production flow, it helps to see the real output. The API Tester runs Read Swiss QR Code directly in the browser: upload a QR-bill PDF, call the endpoint, and see the actual structured JSON response, field names and all, before writing any integration code against it. Getting authenticated against the API in the first place is covered in Connect to the PDF4me V2 API, which lays out the base URL, headers, and request format the code sample above builds on.
The honest limit
This endpoint reads Swiss QR bills. It is built against the Swiss Payments Code standard specifically, not a general-purpose payment-QR decoder for every country's invoicing format. A business handling SEPA or other regional payment QR formats alongside Swiss ones needs to treat those as separate extraction problems, not assume one endpoint covers all of them. Within its actual scope, though, the value is specific and unglamorous in the best way: a field that used to require a human to look at a QR code and know what a Swiss Payments Code block means now arrives as JSON, and the person who used to retype IBANs from scanned invoices gets to stop doing that particular part of their job.
Website: pdf4me.com
Documentation: docs.pdf4me.com
Developer portal: dev.pdf4me.com
Top comments (0)