Generate secure, mobile-optimized ABA Pay QR checkouts for your customers using the Ahnajak gateway â no official merchant keys required.
All payment requests are signed with a SHA-256 HMAC hash to prevent tampering. Never expose your secret_key in client-side code.
sha256(profile_id + transaction_id + amount + secret_key)
You can find your Profile ID and Secret Key in the API Credentials tab of your Dashboard.
Redirect your customers to our hosted ABA Pay checkout page. They'll see a live KHQR code verified by Bakong, with an Open in ABA Mobile deeplink button for one-tap payment.
https://abapay.kesor.cam/api/payment/requestv2/{YOUR_PROFILE_ID}
| Key | Type | Required | Notes |
|---|---|---|---|
| transaction_id | string | REQUIRED | Your internal unique Order ID. Must be unique per transaction. |
| amount | decimal | REQUIRED | USD amount (Min: 0.01). Use format: 12.50 |
| success_url | url | OPTIONAL | URL to redirect customer to after payment. Must be URL-encoded. |
| remark | string | OPTIONAL | Order note or customer username shown on receipt. |
| hash | sha256 | REQUIRED |
sha256(profile_id + transaction_id + amount + secret_key)
|
profile_id is part of the URL path (not a query param). Get it from your API Credentials tab.
After a payment session is created, customers are redirected to the hosted checkout page at this URL pattern:
https://abapay.kesor.cam/payment/khqrcc/{tx_id}
The checkout page automatically shows the QR code, merchant info, countdown timer, and ABA Mobile deeplink button. No extra setup needed.
The simplest integration. Generate the signed URL server-side and redirect the customer directly to the ABA Pay checkout.
// 1. CONFIGURATION $gateway_url = "https://abapay.kesor.cam/api/payment/requestv2"; $profile_id = "YOUR_PROFILE_ID"; $secret_key = "YOUR_SECRET_KEY"; // 2. TRANSACTION DETAILS $payment_data = [ "transaction_id" => "ORDER_" . time(), "amount" => 12.50, "success_url" => "https://yoursite.com/thank-you", "remark" => "Order #88" ]; // 3. SECURITY HASH: sha256(profile_id + transaction_id + amount + secret_key) $raw = $profile_id . $payment_data['transaction_id'] . $payment_data['amount'] . $secret_key; $payment_data['hash'] = hash('sha256', $raw); // 4. REDIRECT CUSTOMER TO ABA CHECKOUT $final_url = $gateway_url . "/" . $profile_id . "?" . http_build_query($payment_data); header("Location: " . $final_url); exit;
Instead of redirecting customers away, embed the ABA Pay checkout inside a responsive modal or bottom-sheet using our client-side JavaScript plugin. Payment status is verified automatically and your callback fires on success.
<?php // 1. SERVER-SIDE: Generate signed checkout URL (keep secret_key private!) $gateway_url = "https://abapay.kesor.cam/api/payment/requestv2"; $profile_id = "YOUR_PROFILE_ID"; $secret_key = "YOUR_SECRET_KEY"; $payment_data = [ "transaction_id" => "ORDER_" . time(), "amount" => 12.50, "success_url" => "https://yoursite.com/thank-you", "remark" => "Order #88" ]; $raw = $profile_id . $payment_data['transaction_id'] . $payment_data['amount'] . $secret_key; $payment_data['hash'] = hash('sha256', $raw); $checkout_url = $gateway_url . "/" . $profile_id . "?" . http_build_query($payment_data); ?> <!-- 1. Include the Checkout Plugin Script --> <script src="https://abapay.kesor.cam/khqrcc-plugin.js"></script> <!-- 2. Trigger the Iframe Modal via JavaScript --> <script> function payWithAhnajak() { const checkoutUrl = "<?php echo $checkout_url; ?>"; KhqrPayway.openCheckout({ checkout_url: checkoutUrl, onSuccess: function(response) { console.log("Payment successful!", response); window.location.href = "/success"; }, onError: function(error) { console.error("Modal closed or payment failed", error); } }); } </script> <!-- 3. Your custom pay button --> <button onclick="payWithAhnajak()"> Pay with ABA Pay </button>
success_url is optional with the plugin. The onSuccess callback fires instead, giving you full control of post-payment flow.
After the customer pays via ABA Mobile, the gateway sends a signed HTTP POST to your Webhook URL (configured in Dashboard â Gateway Setup).
success_urlsuccess_hashsuccess_timesuccess_amountPOST application/jsontransaction_idamountstatus = "SUCCESS"hash (verify this!)Every webhook POST includes a hash field and a X-Ahnajak-Signature header for double-verification.
sha256(transaction_id + amount + secret_key)
hmac-sha256(secret_key, JSON.stringify(payload))
// 1. READ INCOMING POST BODY $raw_body = file_get_contents('php://input'); $data = json_decode($raw_body, true); $secret = 'YOUR_SECRET_KEY'; // 2. VERIFY HEADER SIGNATURE (recommended) $sig_header = $_SERVER['HTTP_X_AHNAJAK_SIGNATURE'] ?? ''; $expected_sig = hash_hmac('sha256', $raw_body, $secret); if (!hash_equals($expected_sig, $sig_header)) { http_response_code(403); exit('Invalid signature'); } // 3. VERIFY PAYLOAD HASH (double-check) $expected_hash = hash('sha256', $data['transaction_id'] . $data['amount'] . $secret ); if ($data['hash'] !== $expected_hash) { http_response_code(403); exit('Hash mismatch'); } // 4. FULFILL THE ORDER â if ($data['status'] === 'SUCCESS') { $order_id = $data['transaction_id']; $amount = $data['amount']; // ... mark order as paid in your database http_response_code(200); echo json_encode(['received' => true]); }
By default the webhook sends transaction_id, amount, status, and hash. You can configure a Custom Payload Template in Dashboard â Gateway Setup to match the exact format your backend expects.
| Template Variable | Value |
|---|---|
| {{transaction_id}} | Your original transaction ID |
| {{amount}} | USD amount as string e.g. "12.50" |
| {{status}} | Always "SUCCESS" on success webhook |
| {{hash}} | sha256(transaction_id + amount + secret_key) |
{
"order_id": "{{transaction_id}}",
"paid_amount": "{{amount}}",
"payment_status": "{{status}}",
"signature": "{{hash}}"
}