Skip to main content

Bakong-KHQR (Unofficial NBC)

YouTube

A Python package for generating payment transactions compliant with the Bakong KHQR standard.

License Python Version PyPI version Socket Security Downloads

📱 Download Mobile App

  • Bakong App Bakong App Apple Store Icon | Google Play Icon

  • Bakong Tourists Bakong Tourists Apple Store Icon | Bakong Icon

📋 Requirement

  • Python 3.8+
  • A Bakong account with full KYC verification
  • An NBC Bakong Developer Token or a Bakong Relay Token (rbk...)
    (Sign up and generate your token at dash.bakongrelay.com)

📦 Installation

pip3 install bakong-khqr

or Update to the Latest Version:

pip3 install --upgrade bakong-khqr

🚀 Key Differences: Bakong Relay vs. NBC Official API

Feature / Behavior Bakong Relay (rbk... token) Bakong NBC (Developer Token / Offline)
API Endpoint https://api.bakongrelay.com/v1 https://api-bakong.nbc.gov.kh/v1
Hosting & IP Restriction Global Access (No Cambodia IP restrictions) Restricted to Cambodia IP addresses
create_qr() Requirements Only amount is strictly required; merchant and currency details are auto-resolved from your RBK Token. Requires account_id, merchant_name, merchant_city, amount, and currency.
Amount Validation Handled directly by Relay Backend (Min USD $0.01 / Min KHR 100). Static or Dynamic offline EMVCo generation.
Transaction States 4 States: PAID, SCANNED, UNPAID, EXPIRED 2 States: PAID, UNPAID
Polling Optimization SCANNED = 3s delay; PAID/EXPIRED = 0s (exit loop). PAID = 0s; UNPAID = 5s–300s window matrix.
Gateway Error Handling Detailed errors (Token expired/over-limit, Maintenance, Rate limit, Store config). Standard NBC error messages.

💻 Usage Guide

When using an rbk... token, create_qr() only requires amount. All merchant and currency details are automatically retrieved from your Store Link configured in the Bakong Relay dashboard.

import time
from bakong_khqr import KHQR

# Initialize with your Bakong Relay Store Token
khqr = KHQR("rbk_live_xxxxxxxxxxxxxxxxxxxx")

# 1. Generate QR Code (amount only; backend auto-detects currency & merchant info)
qr_string = khqr.create_qr(amount=1.50)
print("KHQR String:", qr_string)

# 2. Get MD5 Checksum
md5 = khqr.generate_md5(qr_string)
print("Transaction MD5:", md5)

# 3. Smart Polling Loop (Handles PAID, SCANNED, UNPAID, and EXPIRED)
start_time = time.time()
timeout_seconds = 10 * 60  # 10 minutes

while True:
    status, next_delay = khqr.check_payment(md5, start_time=start_time)
    print(f"Current Status: {status} | Next check in: {next_delay}s")

    if status == "PAID":
        print("🎉 Payment Successful!")
        payment_info = khqr.get_payment(md5)
        print("Transaction Details:", payment_info)
        break

    elif status == "EXPIRED":
        print("❌ Transaction has expired!")
        break

    elif status == "SCANNED":
        print("📱 Customer has scanned the QR. Awaiting PIN/confirmation...")

    # Stop polling if client timeout is reached
    if time.time() - start_time >= timeout_seconds:
        print("🛑 Local polling timeout reached.")
        break

    time.sleep(next_delay)

2. Using Official NBC Token or Offline KHQR Generation

If initialized without a token or with an official NBC Developer Token, the SDK uses the standard EMVCo offline engine:

from bakong_khqr import KHQR

# Without token (Offline EMVCo Generator) or with NBC Token
khqr = KHQR("your_nbc_developer_token_here")

# Full EMVCo parameters are required
qr_string = khqr.create_qr(
    account_id="user_name@bank",
    merchant_name="My Store",
    merchant_city="Phnom Penh",
    amount=10.00,
    currency="USD",
    store_label="Cashier-01",
    phone_number="012345678",
    bill_number="TRX012345",
    terminal_label="POS-01",
    static=False,
    expiration=1
)

md5 = khqr.generate_md5(qr_string)

# Check status via official NBC API (Returns either PAID or UNPAID)
status = khqr.check_payment(md5)
print("Status:", status)

Generate a direct link to open the mobile banking app:

deeplink = khqr.generate_deeplink(
    qr=qr_string,
    appDeepLinkCallback="https://your_website.com/checkout/success](https://your_website.com/checkout/success)",
    appIconUrl="https://your_website.com/images/logo.png](https://your_website.com/images/logo.png)",
    appName="MyStore"
)
print("Deeplink URL:", deeplink)

4. Batch Transaction Verification (check_bulk_payments)

Check multiple transactions in a single API call (Maximum 50 hashes per request):

md5_list = [
    "dfcabf4598d1c405a75540a3d4ca099d", 
    "5154e4f795634ff1a0ae4b48e53a6d9c",
    "a57d9bb85f52f12a20cf7beecb03d11d"
]

# Returns a list of MD5 hashes that are confirmed as PAID
paid_hashes = khqr.check_bulk_payments(md5_list)
print("Paid transactions:", paid_hashes)

5. Generate Styled QR Code Image

Install optional dependencies with pip install "bakong-khqr[image]":

# Generate styled KHQR PNG image
image_path = khqr.qr_image(qr_string, format="png")
print("Saved to:", image_path)

# Or export as Base64 Data URI for web embedding
base64_uri = khqr.qr_image(qr_string, format="base64_uri")
print('<img src="' + base64_uri + '" />')

🧠 Smart Polling Guide for check_payment()

The check_payment() method dynamically adjusts next_delay when start_time is supplied, preserving API quotas and adapting to customer actions:

Transaction State Token Type Recommended Delay Explanation
SCANNED Bakong Relay (rbk...) 3 seconds Customer has scanned the QR code. Tight polling for instant confirmation.
PAID Both 0 seconds Terminal state. Payment confirmed; break out of the loop immediately.
EXPIRED Bakong Relay (rbk...) 0 seconds Terminal state. Session timed out; break out of the loop immediately.
UNPAID (0 – 5 min) Both 5 seconds Active transaction window. High likelihood of scanning.
UNPAID (5 – 15 min) Both 10 seconds Customer might be delayed; reduces request frequency.
UNPAID (15 – 60 min) Both 15 seconds Extended transaction window.
UNPAID (> 60 min) Both 300 seconds (5 min) Dormant or forgotten session; maximum token preservation.

🛠️ Method Reference

  • create_qr(...) -> str: Creates an EMVCo-compliant KHQR string. For rbk tokens, requests api.bakongrelay.com; for NBC tokens or offline use, compiles locally.
  • generate_md5(qr: str) -> str: Computes the 32-character hexadecimal MD5 hash for the QR code.
  • generate_deeplink(...) -> str | None: Generates a mobile banking deep link.
  • check_payment(md5: str, start_time: float | None = None) -> str | tuple[str, int]:
    • Without start_time: Returns status string (PAID, SCANNED, UNPAID, EXPIRED).
    • With start_time: Returns (status, next_delay) tuple.
  • get_payment(md5: str) -> dict | None: Returns transaction details if confirmed PAID. Returns None if SCANNED, UNPAID, or EXPIRED.
  • check_bulk_payments(md5_list: list[str]) -> list[str]: Verifies an array of MD5 hashes (Max 50) and returns a list of paid hashes.
  • qr_image(qr: str, format: str = "png", output_path: str | None = None) -> str | bytes: Exports styled KHQR image in PNG, JPEG, WebP, raw bytes, Base64, or Data URI format.

⚠️ Web Checkout Integration (Coming soon)


📜 License

This project is licensed under the MIT License. See the LICENSE file for details.

📬 Contact & Support

KHQR Donation KHQR Donation

❤️ Sponsors

This project is supported by the community.
👉 List Sponsors & Donors

Metadata

Release files for bakong-khqr 0.6.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bakong-khqr 0.6.3
File Size Uploaded
bakong_khqr-0.6.3.tar.gz 213.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for bakong-khqr 0.6.3
File Interpreter ABI Platform
bakong_khqr-0.6.3-py3-none-any.whl Python 3 none any Details

Total release size: 426.5 kB

Release files / bakong_khqr-0.6.3.tar.gz

Download URL bakong_khqr-0.6.3.tar.gz
Size 213.9 kB
Tags Source
SHA-256 checksum
How to use checksums
bd27fd6eb98849a0e7b18634858ab4b2b524e7fd67eff26608a12a7c5a2ee894
BLAKE2b-256 checksum
How to use checksums
5d36147cffb8f0d745612e857bedd6cc67c578f9c6e40baaca537b46cb1af688
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.

Transparency log

Release files / bakong_khqr-0.6.3-py3-none-any.whl

Download URL bakong_khqr-0.6.3-py3-none-any.whl
Size 212.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fbc15cc387f57f62ecf0fce44c6c5cdd066cd740b18c157e0e0de35d9e684315
BLAKE2b-256 checksum
How to use checksums
20cec522fcb3bd00faf54f941cbb75022de5ad51cb681c4827dba6472d5bf76c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.

Transparency log

Release history Release notifications | RSS feed

0.6.5

2 release files

0.6.4

2 release files

This release

0.6.3 This release

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.9

2 release files

0.5.8

2 release files

0.5.7

2 release files

0.5.6

2 release files

0.5.5

2 release files

0.5.4

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.23

2 release files

0.4.22

2 release files

0.4.21

2 release files

0.4.20

2 release files

0.4.19

2 release files

0.4.18

2 release files

0.4.17

2 release files

0.4.16

2 release files

0.4.15

2 release files

0.4.12

2 release files

0.4.11

2 release files

0.4.10

2 release files

0.4.9

2 release files

0.4.8

2 release files

0.4.7

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page