Skip to content
Appearance

Payment status polling and reconciliation

Give checkout fast feedback without polling forever, then retrieve the complete payment record your order system can reconcile against.

Observe
POST /payment/status
Reconcile
POST /payment/detail
Interval
Every 2–3 seconds
Deadline
expireAt

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.

Read the current payment state
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.

Stop polling at settlement or expiry
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.