View Source QRNBU (NBU payment QR v0.3.3)
NBU (National Bank of Ukraine) QR Code generator library.
This library provides a comprehensive API for generating NBU-compliant QR codes for payment systems in Ukraine. It supports all three official NBU QR code versions:
- V001: Plain text format with CRLF line endings (EPC QR code compatible)
- V002: Base64URL encoded format with 13 fields
- V003: Extended Base64URL format with 17 fields (ISO 20022 category purpose)
Quick Start
# Generate a simple V001 QR code
iex> {:ok, qr} = QRNBU.generate(:v001, %{
...> recipient: "ТОВ Компанія",
...> iban: "UA213223130000026007233566001",
...> recipient_code: "12345678",
...> purpose: "Оплата товарів"
...> })
iex> String.contains?(qr, "BCD")
true
# Generate a V002 QR code with amount
iex> {:ok, qr} = QRNBU.generate(:v002, %{
...> recipient: "ТОВ Компанія",
...> iban: "UA213223130000026007233566001",
...> recipient_code: "12345678",
...> purpose: "Оплата товарів",
...> amount: Decimal.new("100.50")
...> })
iex> String.starts_with?(qr, "https://qr.bank.gov.ua/")
true
# Generate a V003 QR code with extended fields
iex> {:ok, qr} = QRNBU.generate(:v003, %{
...> recipient: "ТОВ Компанія",
...> iban: "UA213223130000026007233566001",
...> recipient_code: "12345678",
...> purpose: "Оплата товарів",
...> amount: Decimal.new("500.00"),
...> category_purpose: "SUPP/REGU"
...> })
iex> String.starts_with?(qr, "https://qr.bank.gov.ua/")
trueVersion Selection
Choose the appropriate version based on your requirements:
- Use V001 for compatibility with EPC QR codes and simple payments
- Use V002 for modern NBU-compliant payments with Base64URL encoding
- Use V003 for advanced features like ISO 20022 category purpose and field locking
Field Reference
Common Fields (All Versions)
:recipient(required) - Recipient name (1-70 characters):iban(required) - Bank account IBAN (UA + 27 digits):recipient_code(required) - EDRPOU/IPN/Tax ID (6-35 characters):purpose(required) - Payment purpose (1-140 characters):amount(optional) - Payment amount asDecimal.t():function(optional) - Function code::uct,:ict, or:xct(default::uct):encoding(optional) - Character encoding::utf8or:cp1251(default::utf8)
V002 Additional Fields
:reference(optional) - Payment reference number (max 35 characters)
V003 Additional Fields
:reference(optional) - Payment reference number (max 35 characters):unique_recipient_id(optional) - Unique recipient identifier (max 35 characters):category_purpose(optional) - ISO 20022 category purpose (format:CCCC/PPPP):display(optional) - Display text for QR scanner (max 140 characters):field_lock(optional) - Field lock bitmap0x0000-0xFFFF(integer):invoice_validity(optional) - Invoice expiration asNaiveDateTime.t():invoice_creation(optional) - Invoice creation asNaiveDateTime.t():digital_signature(optional) - Digital signature string (max 1000 characters)
Error Handling
All functions return {:ok, result} or {:error, reason} tuples.
Common errors:
- Missing required fields
- Invalid field formats (IBAN, tax ID, etc.)
- Invalid character encoding
- Date/time validation failures
References
- NBU Resolution No. 97, August 19, 2025
- EPC QR Code Guidelines v3.0
- ISO 20022 External Code Sets
Summary
Functions
Detects the version of an NBU QR code string.
Generates an NBU QR code string for the specified version.
Generates an NBU QR code string, raising an exception on error.
Validates NBU QR code data without generating the QR string.
Types
Functions
Detects the version of an NBU QR code string.
Analyzes the QR code format to determine which version it represents.
Returns
{:ok, :v001}- Plain text format with BCD marker{:ok, :v002}- Base64URL with NBU URL prefix{:ok, :v003}- Base64URL with NBU URL prefix (distinguished by field count){:error, reason}- Unable to detect version
Examples
iex> v001_str = String.duplicate(" ", 23) <> "\r\nBCD\r\n001\r\n"
iex> QRNBU.detect_version(v001_str)
{:ok, :v001}
iex> QRNBU.detect_version("invalid")
{:error, "Unable to detect QR code version"}
Generates an NBU QR code string for the specified version.
Parameters
version- QR code version::v001,:v002, or:v003data- Map containing QR code fields (see module documentation)
Returns
{:ok, qr_string}- Successfully generated QR code string{:error, reason}- Validation or encoding error
Examples
iex> {:ok, qr} = QRNBU.generate(:v001, %{
...> recipient: "ТОВ Компанія",
...> iban: "UA213223130000026007233566001",
...> recipient_code: "12345678",
...> purpose: "Оплата товарів"
...> })
iex> is_binary(qr)
true
iex> {:ok, qr} = QRNBU.generate(:v002, %{
...> recipient: "ТОВ Компанія",
...> iban: "UA213223130000026007233566001",
...> recipient_code: "12345678",
...> purpose: "Оплата товарів",
...> amount: Decimal.new("100.50"),
...> reference: "INV-001"
...> })
iex> String.starts_with?(qr, "https://qr.bank.gov.ua/")
true
iex> QRNBU.generate(:invalid_version, %{})
{:error, "Invalid version: :invalid_version. Must be :v001, :v002, or :v003"}
iex> {:error, reason} = QRNBU.generate(:v001, %{})
iex> is_binary(reason)
true
Generates an NBU QR code string, raising an exception on error.
Same as generate/2 but raises RuntimeError instead of returning an error tuple.
Examples
iex> qr = QRNBU.generate!(:v001, %{
...> recipient: "ТОВ Компанія",
...> iban: "UA213223130000026007233566001",
...> recipient_code: "12345678",
...> purpose: "Оплата товарів"
...> })
iex> is_binary(qr) and String.contains?(qr, "BCD")
true
Validates NBU QR code data without generating the QR string.
Useful for pre-validation before QR code generation.
Parameters
version- QR code version::v001,:v002, or:v003data- Map containing QR code fields
Returns
:ok- Data is valid for the specified version{:error, reason}- Validation error
Examples
iex> QRNBU.validate(:v001, %{
...> recipient: "ТОВ Компанія",
...> iban: "UA213223130000026007233566001",
...> recipient_code: "12345678",
...> purpose: "Оплата товарів"
...> })
:ok
iex> QRNBU.validate(:v001, %{})
{:error, "Missing required field: recipient"}
iex> QRNBU.validate(:v003, %{
...> recipient: "ТОВ Компанія",
...> iban: "UA213223130000026007233566001",
...> recipient_code: "12345678",
...> purpose: "Оплата товарів",
...> field_lock: -1
...> })
{:error, "Field lock must be between 0 and 65535"}