Generate VietQR for python following VietQR Vi Version and En Version
- Documentation: https://shinxz12.github.io/napas-qr-python
- GitHub: https://github.com/shinxz12/napas-qr-python
- PyPI: https://pypi.org/project/napas-qr-python/
- Free software: MIT
- VietQR code encoder.
- VietQR code decoder with CRC verification.
- Using segno for QR generator.
All root and template fields from the NAPAS247 spec are supported.
| Field | ID | Mandatory | Default | Description |
|---|---|---|---|---|
| bin_id | 38.01.00 | Yes | None | Beneficiary BIN / bank code |
| consumer_id | 38.01.01 | Yes | None | Card / account ID |
| service_code | 38.02 | Yes | "ACCOUNT" | "PAYMENT", "CASH_WITHDRAWL", "CARD", "ACCOUNT" |
| glocal_uuid | 38.00 | No | "A000000727" | NAPAS AID (GUID) |
| payload_format_indicator | 00 | No | "01" | Payload format version |
| point_of_initiation_method | 01 | Yes | "DYNAMIC" | "STATIC" (11) or "DYNAMIC" (12) |
| merchant_category_code | 52 | No | None | MCC (ISO 18245) |
| transaction_currency | 53 | Yes | "704" (VND) | Currency (ISO 4217) |
| transaction_amount | 54 | No | None | Amount |
| tip_or_convenience_indicator | 55 | No | None | "01", "02" or "03" |
| convenience_fee_fixed | 56 | No | None | Fixed fee (when indicator = 02) |
| convenience_fee_percentage | 57 | No | None | Percentage fee (when indicator = 03) |
| country_code | 58 | Yes | "VN" | Country (ISO 3166-1 alpha-2) |
| merchant_name | 59 | No | None | Merchant name |
| merchant_city | 60 | No | None | Merchant city |
| postal_code | 61 | No | None | Postal code |
| bill_number | 62.01 | No | None | Bill number |
| mobile_number | 62.02 | No | None | Mobile number |
| store_label | 62.03 | No | None | Store label |
| loyalty_number | 62.04 | No | None | Loyalty number |
| reference_label | 62.05 | No | None | Reference label |
| customer_label | 62.06 | No | None | Customer label |
| terminal_label | 62.07 | No | None | Terminal label |
| purpose_of_transaction | 62.08 | No | None | Purpose / message |
| additional_consumer_data_request | 62.09 | No | None | "A", "M", "E" combination |
| language_preference | 64.00 | No | None | Alternate language (ISO 639) |
| merchant_name_alt | 64.01 | No | None | Merchant name (alternate language) |
| merchant_city_alt | 64.02 | No | None | Merchant city (alternate language) |
Please read more in the VietQR docs.
- Generate code with base informations and an account service:
from qr_pay import QRPay
qr_pay = QRPay('970436', '1031933430', purpose_of_transaction="Thanh toan hoa don")
code = qr_pay.code
# 00020101021238540010A00000072701240006970436011010319334300208QRIBFTTA53037045802VN62220818Thanh toan hoa don6304E8A4
# Generate QR code
qr_pay.generate_qr_pay()
- Generate code with a card service and amount:
data = {
"bin_id": "970436",
"consumer_id": "9704368625581601018",
"service_code": "CARD",
"transaction_amount": 2000000
}
qr_pay = QRPay(**data)
code = qr_pay.code
# 00020101021238630010A00000072701330006970436011997043686255816010180208QRIBFTTC5303704540720000005802VN6304A2DC
qr_pay.generate_qr_pay()
- Generate QR code with custom styles following segno:
qr_pay = QRPay('970436', '1031933430')
# Code: 00020101021238540010A00000072701240006970436011010319334300208QRIBFTTA53037045802VN630424AB
styles = { "scale": 2, "dark": "darkblue"}
dist = "qr_code_style.png"
qr_pay.generate_qr_pay(dist=dist, styles=styles)
Parse a raw VietQR payload back into fields. The CRC is verified by default
(raises qr_pay.decode.QRDecodeError on mismatch or malformed input).
from qr_pay import QRPay, decode
code = "00020101021238570010A00000072701270006970403011300110123456780208QRIBFTTA530370454061800005802VN62340107NPS68690819thanh toan don hang63042E2E"
# As a dict of fields
data = decode(code)
# {'bin_id': '970403', 'consumer_id': '0011012345678', 'service_code': 'QRIBFTTA',
# 'transaction_amount': '180000', 'point_of_initiation_method': '12',
# 'purpose_of_transaction': 'thanh toan don hang', ...}
# As a QRPay instance (re-encodable)
qr_pay = QRPay.decode(code)
assert qr_pay.bin_id == "970403"
# Skip CRC verification for non-standard payloads
data = decode(code, verify_crc=False)
# Low-level nested EMVCo TLV objects
root = QRPay.parse(code)
root["38"].children["01"].get("00") # -> '970403' (BIN)Installing the package exposes a napas_qr command with encode and decode
subcommands.
# Encode fields into a payload (and optionally write a QR image)
$ napas_qr encode --bin 970436 --consumer 1031933430 --amount 50000 --purpose "Thanh toan"
00020101021238540010A00000072701240006970436011010319334300208QRIBFTTA53037045405500005802VN62140810Thanh toan630438A6
$ napas_qr encode --bin 970436 --consumer 1031933430 --qr qr.png
# Decode a payload into JSON (CRC verified by default)
$ napas_qr decode "00020101021238570010A00000072701270006970403011300110123456780208QRIBFTTA530370454061800005802VN62340107NPS68690819thanh toan don hang63042E2E"
{
"point_of_initiation_method": "12",
"bin_id": "970403",
"consumer_id": "0011012345678",
"transaction_amount": "180000",
"purpose_of_transaction": "thanh toan don hang",
...
}
# Decode without CRC verification
$ napas_qr decode "<payload>" --no-verifyFull option list: napas_qr encode --help / napas_qr decode --help.