Use the lightweight status route
The status endpoint is the observation channel for an active checkout; the detail endpoint is the durable record used afterward.
Send a store identifier plus either Bongluy's payment UUID inid or your owntranId. When both payment identifiers are present, id wins.
curl -X POST https://api.bongluy.com/payment/status \
-H "Authorization: Bearer $BONGLUY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"merchantStoreId": "branch-2",
"tranId": "INV-1042"
}'The status response uses epoch milliseconds forexpireAt and at. The payment object returned by create and detail uses an ISO 8601 expiry, so do not parse the two response shapes as if they were identical.
Branch on four payment states
State names are stable machine values; time is still part of the decision because an upstream retry can leave a stale record pending past expiry.
PENDING- Created and awaiting payment.
SUCCESS- Paid and settled.
EXPIRED- Expired without payment.
FAILED- Reserved for a future non-success terminal state.
Use a bounded polling loop
Poll every two or three seconds, stop when the state leaves PENDING, and stop at the returned deadline even if no terminal update arrives.
async function waitForPayment(payment) {
const deadline = new Date(payment.expireAt).getTime();
while (Date.now() < deadline) {
const result = await readStatus(payment.tranId);
if (result.status !== "PENDING") return result.status;
await new Promise((resolve) => setTimeout(resolve, 2500));
}
return "EXPIRED";
}Poll once per payment from your server or one active checkout, not from every browser tab. Authenticated routes are limited per API key, so duplicate loops waste capacity without making settlement arrive sooner.
Read detail for the durable record
After success, use POST /payment/detail to retrieve the full record required for receipts and order reconciliation.
The detail response contains the amount, currency, your transaction id, settled transaction id, receipt URL, settlement time, QR, deeplinks, and timestamps. Match it to your order using the sametranId supplied during creation.
Merchant webhooks are not available yet. Polling provides checkout feedback today; a later detail read provides the durable source for reconciliation.
Retry without creating a duplicate
A network timeout does not prove the original create failed, so retry the create request with the same store and transaction id.
Bongluy uses tranId as the idempotency key within a store. Reusing it resolves to the original payment; changing it requests a new payment. On authentication or rate-limit errors, fix the key or back off before polling again rather than replacing the transaction id.
Continue the integration
Read KHQR API guide next, or use the complete API reference for request fields, response shapes, limits, and error behavior.