A payment QR code is just twelve lines of text
The creator of ibanchecker.cash breaks down the EPC069-12 standard, revealing how payment QR codes are built using simple plain text and strict byte limits.

Stock photo for illustration only, not from the actual event
- The EPC069-12 standard uses twelve lines of plain text without binary framing or JSON.
- The entire payload must fit within 331 bytes and supports only the euro currency.
- Decoding happens completely inside the browser using jsQR with zero image uploads.
If you have paid an invoice in Europe recently, you have likely pointed your banking app at a small square to automatically fill in the payee, IBAN, and amount. Koray Köylü, creator of ibanchecker.cash, spent weeks working on both sides of these squares by generating and reading them, discovering that the format is far simpler than most expect.
The standard is EPC069-12, published by the European Payments Council and marketed in Germany as a GiroCode. There is no binary framing and no JSON; the payload consists of plain text with twelve elements separated by line breaks:
- 1. Service tag: BCD
- 2. Version: 002 (making the BIC optional)
- 3. Character set: 1 for UTF-8
- 4. Identification: SCT (SEPA Credit Transfer)
- 5. BIC: COBADEFF
- 6. Beneficiary name: Who gets paid
- 7. IBAN: The bank account
- 8. Amount: Currency glued to the value
- 9. Purpose: Empty
- 10. Structured reference: Empty
- 11. Unstructured reference: Free text
- 12. Beneficiary to originator: May be absent
Crucial implementation rules dictate that the entire payload must fit within 331 bytes. The name is capped at 70 characters and the reference at 140. Amounts are strictly in euros from 0.01 to 999,999,999.99, error correction must be level M, and there is no digital signature proving who generated the code—something to keep in mind when encountering stickers on parking meters.

Stock photo for illustration only, not from the actual event
Line 6 represents the beneficiary name. An early bug in Köylü's generator accidentally pulled the bank name instead, causing banking apps to display "Commerzbank" rather than the actual account holder. The developer strongly emphasizes that line 6 must always be the payee, never the bank.
"A payment QR code is just twelve lines of text"
Koray Köylü
The SEPA Credit Transfer (SCT) framework forms the backbone of European cross-border transactions. Structuring payment QR codes as simple plain-text line breaks democratizes implementation for developers, removing heavy software dependencies. However, the absence of cryptographic signatures in the EPC standard highlights the vulnerability of physical QR code stickers, underscoring the need for careful client-side verification.
The updated tool features live code updates as you type, tracking byte progression toward the 331-byte ceiling. Exports include SVG, high-resolution PNG, and vector PDF generated via raw SVG path rendering with zero dependencies. On the decoding side, dropped images are parsed locally via a dynamically imported jsQR module, ensuring user privacy by keeping image data strictly in the browser.
Source: Dev.to
Found something wrong in this article? Report an issue with this article
Comments
Leave a Comment