Skip to content

Latest commit

 

History

History
394 lines (282 loc) · 14.2 KB

File metadata and controls

394 lines (282 loc) · 14.2 KB

Bakong API Integration with Spring Boot

A Spring Boot project demonstrating how to integrate with the Bakong Open API and KHQR SDK — Cambodia's official QR payment system developed by the National Bank of Cambodia (NBC). This project covers generating KHQR payment QR codes, rendering scannable QR images, and verifying transactions using the Bakong Java SDK.

🇰🇭 If you are a developer in Cambodia looking to integrate Bakong QR payment, KHQR, or the NBC Open API into your Java or Spring Boot application — this project is for you.


📋 Table of Contents


Prerequisites

Before starting the integration, you need to:

  1. Create a Bakong Account — Register at https://bakong.nbc.gov.kh and get your account verified.
  2. Register with Bakong Open API — Sign up with your email at https://api-bakong.nbc.gov.kh/ to receive your Bearer Token for API access.

Resources & Documentation

Read these documents before starting the integration. All PDFs are also available locally inside the integration/ folder of this project.

Resource Description Link
Bakong Open API Document Core API reference for authentication and endpoints Download PDF
KHQR SDK Document Guide for using the KHQR Java SDK Download PDF
KHQR Card Guideline Official UI/design guideline for KHQR card display Download PDF
Postman Collection Ready-to-use API collection for testing all endpoints integration/Bakong-API-Integration.postman_collection.json
Bakong Open API Portal Register and get your Bearer Token https://api-bakong.nbc.gov.kh/

Project Setup

Clone or create a Spring Boot project and add the required dependencies listed below.


Dependencies

Add the following to your build.gradle:

implementation 'org.springframework.boot:spring-boot-starter-webmvc'

// Bakong KHQR SDK
implementation 'kh.gov.nbc.bakong_khqr:sdk-java:1.0.0.16'

// QR code image generation (ZXing)
implementation 'com.google.zxing:core:3.5.3'
implementation 'com.google.zxing:javase:3.5.3'

// JSON parsing
implementation 'com.fasterxml.jackson.core:jackson-databind'

// Validation
implementation 'org.springframework.boot:spring-boot-starter-validation'

// Lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

💡 This project uses Spring RestClient (available since Spring Boot 3.2) instead of RestTemplate for all HTTP calls to the Bakong Open API. No extra dependency is needed — it is included in spring-boot-starter-webmvc.


Configuration

application.properties

spring.application.name=bakong-api-integration

# Bakong Configuration
bakong.account-id=${BAKONG_ACCOUNT_ID}
bakong.base-url=${BAKONG_BASE_URL}
bakong.email=${EMAIL}

application-dev.properties

BAKONG_ACCOUNT_ID=your_bakong_id@bank
BAKONG_BASE_URL=https://api-bakong.nbc.gov.kh
EMAIL=your_registered_email@example.com

⚠️ Security Warning: Never commit real credentials to version control. Use environment variables or a secrets manager in production.

💡 Simplified config. Only 3 properties are needed: your Bakong account ID, the API base URL, and your registered email. The BakongTokenService handles token fetching and renewal automatically.


Token Auto-Renewal

Previously, you had to manually copy and paste the Bearer Token from the Bakong portal into your config. This project handles token management automatically.

The BakongTokenService works as follows:

  1. On the first request, it calls the Bakong /v1/renew_token endpoint using your registered email address
  2. It decodes the returned JWT to read the real expiry time (exp claim)
  3. The token is cached in memory — subsequent requests reuse it without hitting the API again
  4. When the token is expired, it automatically fetches a new one

This means you only need to provide your EMAIL in the config — no manual token copying needed.

POST /v1/renew_token
Body: { "email": "your_registered_email@example.com" }

🔒 The token is stored in memory only (not on disk). It is renewed per application instance and resets on restart.

🔄 This project uses Spring RestClient (introduced in Spring Boot 3.2) instead of the older RestTemplate for all HTTP calls to the Bakong Open API.


API Endpoints

All endpoints are prefixed with /api/v1/bakong.

Method Endpoint Description
POST /generate-qr Generates a KHQR string and MD5 hash
POST /get-qr-image Converts a KHQR string into a scannable PNG image
POST /check-transaction Checks if a transaction has been completed using its MD5 hash

Usage Guide

Follow these steps in order to complete a payment flow:

Step 1 — Generate QR Code

Call the generate-qr endpoint with the payment amount. This returns a KHQR string and an MD5 hash.

Request:

POST http://localhost:8080/api/v1/bakong/generate-qr
Content-Type: application/json

{
    "amount": 0.1
}

All fields except amount are optional — default values will be applied automatically if not provided. See the full request fields below:

Field Type Default
currency KHQRCurrency KHR
amount Double (required)
merchantName String DEFAULT MERCHANT
merchantCity String PHNOM PENH
merchantId String DEFAULT MERCHANT ID
acquiringBank String DEFAULT BANK
upiAccountInformation String null
expirationTimestamp Integer 15
billNumber String BILL123456
storeLabel String STORE
terminalLabel String TERMINAL1
mobileNumber String 012345678
purposeOfTransaction String Payment
merchantAlternateLanguagePreference String km
merchantNameAlternateLanguage String អ្នកលក់
merchantCityAlternateLanguage String ភ្នំពេញ

Response:

{
  "KHQRStatus": {
    "code": 0,
    "errorCode": null,
    "message": null
  },
  "data": {
    "md5": "2e8787edaddc31ffe9c572923db06d33",
    "qr": "0002010102121511KH12345678930360014bora_tong@aclb0106..."
  }
}

Save both the qr string and the md5 value — you will need them in the next steps.


Step 2 — Get QR Image

Pass the qr string from Step 1 to generate a scannable PNG QR code image.

Request:

POST http://localhost:8080/api/v1/bakong/get-qr-image
Content-Type: application/json

{
    "qr": "0002010102121511KH12345678930360014bora_tong@aclb0106...",
    "md5": "2e8787edaddc31ffe9c572923db06d33"
}

Response:

The endpoint returns a PNG image (image/png). Display or download the image so the customer can scan it using the Bakong app to complete the payment.


Step 3 — Check Transaction Status

After the customer scans and pays, use the md5 hash from Step 1 to verify whether the payment was successful.

The response is mapped to a BakongResponse record:

public record BakongResponse(
        int responseCode,
        String responseMessage,
        Integer errorCode,
        Object data
)

responseCode: 0 — Transaction successful ❌ responseCode: 1 — Transaction not found or not yet paid

Request:

POST http://localhost:8080/api/v1/bakong/check-transaction
Content-Type: application/json

{
    "md5": "2e8787edaddc31ffe9c572923db06d33"
}

Response — Payment Successful (responseCode: 0):

{
  "responseCode": 0,
  "responseMessage": "Success",
  "data": {
    "hash": "bf917e9534cac3595ee5dc5a9e7d3b120b6143ff3b368c244189cf22ed9af877",
    "fromAccountId": "customer@bank",
    "toAccountId": "bora_tong@aclb",
    "currency": "USD",
    "amount": 0.1,
    "description": null,
    "createdDateMs": 1772125349000,
    "acknowledgedDateMs": 1772125351000,
    "externalRef": "100FT36931627892"
  }
}

Response — Payment Not Found (responseCode: 1):

{
  "responseCode": 1,
  "responseMessage": "Transaction could not be found. Please check and try again.",
  "errorCode": 1,
  "data": null
}

💡 You can check responseCode in your frontend or backend logic to determine the payment status:

  • responseCode == 0 → Payment confirmed, proceed with order
  • responseCode == 1 → Payment not yet made or MD5 is incorrect

KHQR Card UI Design

The KHQR Card is a standardized payment card UI that displays the KHQR logo, merchant name, payment amount, and the scannable QR code. This is what a customer sees when they are about to make a payment.

🎨 You are responsible for designing and building this UI yourself. The National Bank of Cambodia (NBC) provides strict branding guidelines that must be followed when displaying KHQR in any application.

Design Guidelines

Download and follow the official KHQR Card Guideline from NBC:

📄 KHQR Card Guideline PDF

The guideline covers:

  • Correct usage of the KHQR logo (color, size, placement)
  • Card layout, proportions, and color palette
  • Typography and font rules
  • Dos and Don'ts for displaying the QR code
  • Safe zones and spacing requirements

Example Card Layout

KHQR Card Example

How to Build It

  1. Call /generate-qr to get the qr string and md5.
  2. Call /get-qr-image with the qr string to get the PNG image.
  3. Display the image inside your custom-designed KHQR card UI.
  4. Use the official logos and assets from the KHQR - asset/ folder (see KHQR Assets below).
  5. Follow the card guideline PDF strictly for correct branding.

KHQR Assets

Official KHQR brand assets are included in the KHQR - asset/ folder of this project. These assets are provided by the National Bank of Cambodia and must be used as-is according to the KHQR branding guidelines.

File Format Usage
KHQR Logo red.png / .svg / .jpg PNG, SVG, JPG Primary KHQR logo on red background — use in card header
KHQR Logo.png / .svg / .jpg PNG, SVG, JPG KHQR logo on white/transparent background
KHQR available here - logo with bg.png / .svg / .jpg PNG, SVG, JPG "KHQR Available Here" badge — use at point of sale
KHQR - digital payment.svg SVG Digital payment banner graphic
QR Stand for export.svg SVG QR stand display for physical/print usage
QR Tag.svg SVG QR tag for labeling or printing

💡 Tip: Use the .svg versions whenever possible for sharp rendering at any screen size. Use .png for environments that do not support SVG.

⚠️ Do not modify, recolor, or distort any of the official KHQR assets. Refer to the KHQR Card Guideline for approved usage rules.


Project Structure

src/
├── main/
│   ├── java/
│   │   └── com.tongbora.bakongapiintergration/
│   │       ├── config/
│   │       │   └── JacksonConfig.java           # Jackson ObjectMapper
│   │       ├── controller/
│   │       │   └── BakongController.java        # REST API endpoints
│   │       ├── dto/
│   │       │   ├── BakongRequest.java           # Request DTO (amount)
│   │       │   ├── BakongResponse.java          # Response DTO
│   │       │   └── CheckTransactionRequest.java # Check transaction DTO
│   │       ├── service/
│   │       │   ├── BakongService.java           # Service interface
│   │       │   ├── BakongTokenService.java      # Token service interface
│   │       │   └── impl/
│   │       │       ├── BakongServiceImpl.java   # Business logic
│   │       │       └── BakongTokenServiceImpl.java # Token auto-renewal (uses RestClient)
│   │       └── BakongApiIntergrationApplication.java
│   └── resources/
│       ├── static/
│       ├── templates/
│       ├── application.properties
│       └── application-dev.properties
└── test/

📁 The project also includes an integration/ folder containing the Bakong Open API Document, KHQR SDK Document, and the Postman collection. A KHQR - asset/ folder with official KHQR brand assets is also included. You can download both directly from the project repository.


Notes

  • Token Auto-Renewal: The app automatically renews the Bearer Token using your registered email. You no longer need to manually copy tokens from the Bakong portal.
  • Production Restriction: The check-transaction endpoint can only be called from servers located in Cambodia in a production environment. Calls from servers outside Cambodia will be blocked.
  • Currency: The example uses USD. You can change the currency to KHR by modifying the KHQRCurrency setting in MerchantInfo.
  • Customization: The MerchantInfo object (merchant name, city, bill number, etc.) should be updated to match your actual business information before going to production.
  • Branding Compliance: When displaying KHQR in any customer-facing UI, always follow the official KHQR Card Guideline and use only the approved assets from the KHQR - asset/ folder.

License

This project is for educational and integration reference purposes.