EPC QR Codes — The EU's Scan-to-Pay Standard for Bank Transfers
If you've ever received an invoice in Germany, Belgium, or the Netherlands and noticed a QR code in the corner that your banking app could scan to pre-fill a transfer — that's an EPC QR code. It's a quiet little standard that does something genuinely useful: eliminates the typo-prone ritual of manually entering an IBAN, amount, and payment reference.
What It Is
The EPC QR code (European Payments Council Quick Response Code) is an open standard for encoding a SEPA Credit Transfer (SCT) into a QR code. You put it on an invoice, a donation page, or a point-of-sale display. The payer scans it with their banking app; the app pre-fills the recipient's IBAN, name, amount, and payment reference. They confirm. Done.
The European Payments Council published the first version in February 2013. The latest version is 2.10, published June 2024. It's also called Girocode in Germany and Zahlen mit Code ("Pay with Code") in Austria.
Countries where banking apps actively support it:
- 🇦🇹 Austria (pioneer — STUZZA defined the format in 2012 before EPC standardised it)
- 🇧🇪 Belgium
- 🇫🇮 Finland (adopted 2015)
- 🇩🇪 Germany (adopted 2015)
- 🇳🇱 Netherlands (adopted 2016)
Support is patchy elsewhere in the SEPA zone — the standard exists, but not every bank has built the scanner into their app.
The Format
The QR code contains plain text, newline-delimited, in a fixed field order. That's it. No JSON, no binary, no encryption. Just a structured text payload that any QR generator can produce.
Here's what a real payload looks like — a €1 payment to the Red Cross of Belgium:
BCD
001
1
SCT
BPOTBEB1
Red Cross of Belgium
BE72000000001616
EUR1.00
CHAR
Urgency fund
Sample EPC QR code
Line by line:
| Line | Field | Example | Notes |
|---|---|---|---|
| 1 | Service Tag | BCD |
Always BCD. Identifies this as an EPC QR code. |
| 2 | Version | 001 or 002 |
001 = BIC required; 002 = BIC optional |
| 3 | Character set | 1 |
1 = UTF-8 (most common) |
| 4 | Identification | SCT |
Always SCT (SEPA Credit Transfer) |
| 5 | BIC | BPOTBEB1 |
Beneficiary bank's BIC. Optional in v2 within SEPA area. |
| 6 | Name | Red Cross of Belgium |
Beneficiary name, max 70 characters |
| 7 | IBAN | BE72000000001616 |
Beneficiary account, max 34 chars |
| 8 | Amount | EUR1.00 |
EUR + amount, e.g. EUR12.50. Max: EUR999,999,999.99. Omit for open amounts. |
| 9 | Purpose | CHAR |
Optional 4-char purpose code (e.g. CHAR = charitable donation) |
| 10 | Structured ref | (empty) | ISO 11649 creditor reference (structured). Mutually exclusive with line 11. |
| 11 | Unstructured ref | Urgency fund |
Free-text payment reference, max 140 chars |
| 12 | Beneficiary info | Sample EPC QR code |
Optional note from payee to payer, max 70 chars |
Key rules:
- Lines 10 and 11 are mutually exclusive — use one or the other, never both
- Empty lines are allowed and required as placeholders for optional fields
- The payload must not exceed 331 bytes in UTF-8 (QR capacity constraint)
- QR error correction level should be M (15% recovery)
Version 1 vs Version 2
Version 1 requires a BIC. Version 2 (released 2016) makes BIC optional within the SEPA zone, since any bank within SEPA can route to an IBAN alone. For new implementations, always use version 2 — less data means a less dense QR code, which is easier to scan.
Character Sets
The spec supports 8 character sets, encoded as an integer on line 3:
| Code | Encoding |
|---|---|
| 1 | UTF-8 |
| 2 | ISO 8859-1 (Latin-1) |
| 3 | ISO 8859-2 |
| 4 | ISO 8859-4 |
| 5 | ISO 8859-5 |
| 6 | ISO 8859-7 (Greek) |
| 7 | ISO 8859-10 |
| 8 | ISO 8859-15 |
Use 1 (UTF-8) unless you have a specific reason not to.
Generating One in Code
It's basically a string concatenation job. Here's the core in JavaScript:
function buildEpcPayload({ bic = '', name, iban, amount, ref = '', info = '' }) {
const version = bic ? '001' : '002';
const amountStr = amount != null ? `EUR${Number(amount).toFixed(2)}` : '';
const lines = [
'BCD', // service tag
version, // version
'1', // UTF-8
'SCT', // identification
bic, // BIC (or empty)
name, // beneficiary name
iban, // IBAN
amountStr, // amount (or empty for open)
'', // purpose code (omitted)
'', // structured reference (omitted)
info || ref, // unstructured reference or info
];
return lines.join('\n');
}
Feed that string into any QR library (qrcode.js, python-qrcode, etc.) and you're done.
For open-amount invoices — where the payer enters the amount themselves — omit the amount field entirely (empty line 8). Some banking apps support this; others don't.
The Amount Field Quirks
A few gotchas:
- Format:
EURfollowed immediately by the number, no space —EUR12.50notEUR 12.50 - Maximum: EUR999,999,999.99 — anything higher isn't valid
- Omitted: Leave line 8 empty for an open/unspecified amount
- Decimals: Use a period (
.) as the decimal separator regardless of locale - Whole amounts:
EUR10.00orEUR10— both should work, butEUR10.00is safer
Why It's Not Everywhere
The EPC QR standard is SEPA-wide — 36 countries in scope — but bank app support is concentrated in the 5 countries above. A few reasons:
- No mandate: EPC published guidelines, not a requirement. Banks adopt it voluntarily.
- Competing standards: Finland has its own variant (via FFI). Belgium has a structured creditor reference variant ("OGM/VCS"). These are compatible but slightly different in usage.
- App investment: Building and maintaining QR scanning in a banking app isn't free. Smaller banks deprioritise it.
- Consumer education: If nobody knows the code exists, nobody asks for it.
That said, adoption has been quietly growing. German banks in particular have pushed Girocode hard — it's common on invoices from small businesses and freelancers there.
Practical Uses
Invoices — the main use case. Put an EPC QR alongside your bank details. Your client in Germany or the Netherlands scans it, all fields pre-fill, they confirm. Faster for them, fewer wrong-IBAN calls for you.
Donation pages — charities in Belgium and Austria have used these for years. Print on a flyer, scan at an event.
Point of sale — display a QR at a market stall or café for bank transfer payments. Not as instant as card, but zero fees compared to Stripe.
Invoicing software — most European invoicing tools now auto-generate these. If yours doesn't, it should.
Online Generators
- c.pixeldev.eu — the generator I built for this site. Live preview, download PNG, copy raw payload. No trackers, no sign-up.
- epc-qr.eu — free, no trackers, has an API:
https://epc-qr.eu?iban=...&euro=...&bname=... - www.europeanpaymentscouncil.eu — the official spec document (free PDF)
The epc-qr.eu API is genuinely handy for dynamic server-side generation — you can hit it with query params and get a PNG back directly.
The Bottom Line
EPC QR codes are a small, elegant piece of EU payments infrastructure that doesn't get nearly enough attention. The format is simple to understand and trivial to implement. If you're building invoicing tools, payment pages, or anything that involves asking someone in the SEPA zone to transfer money — add one. It takes 20 lines of code to generate and eliminates an entire category of "I mistyped the IBAN" support tickets.