Handling the Callback

ជំពូកនេះមិនទាន់ត្រូវបានបកប្រែជាភាសាខ្មែរនៅឡើយទេ — សូមអានជាភាសាអង់គ្លេសខាងក្រោម។

Table of Contents

  1. What the callback is for
  2. A minimal callback handler
  3. Whitelisting your return_url
  4. Testing locally with ngrok
  5. Beginner Pitfalls

1. What the callback is for

After the customer completes (or cancels) payment, PayWay sends a POST request to a return_url you configure — on your server, not your browser. This is how you actually confirm the payment succeeded; never trust the frontend alone.

Your return_url endpoint should:

  • Accept POST with a JSON body.
  • Read the status and tran_id fields.
  • Mark that order as paid in your own database.

For a beginner sandbox exercise, it's enough to log the callback body and print something like "Payment received for tran_id X." Production-grade verification — checking the callback is genuinely from PayWay, not spoofed — is its own lesson, covered in Part 6.

2. A minimal callback handler

router.post('/payment-callback', (req, res) => {
  console.log('Received PayWay callback:', req.body);
  // TODO: verify signature/authenticity of this callback before trusting it
  // TODO: look up the order by tran_id and mark it paid/failed
  res.sendStatus(200);
});

This is intentionally incomplete — it logs and acknowledges, nothing more. Treat the two TODOs as the actual lesson here, not something to silently "finish" without flagging that it needs verification against PayWay's current docs first.

3. Whitelisting your return_url

Whitelist your return_url domain before testing callbacks. PayWay validates return_url against a domain whitelist tied to your merchant profile — error codes 6 ("Requested domain is not in whitelist") and 81 ("The return URL is not in the whitelist"). If your domain isn't whitelisted, PayWay silently never calls back — no error surfaces to your app, which makes this easy to mistake for a bug in your own code.

Contact ABA PayWay's integration team with your domain (or your ngrok tunnel domain, for local testing) to get it whitelisted before testing callbacks.

Also note: a purchase response of code: "00" / "Success!" only means the transaction request was accepted — it does not mean the customer completed payment. The callback only fires once the customer actually approves it (e.g. scanning the KHQR code and confirming in the ABA Mobile app).

4. Testing locally with ngrok

PayWay's callback requires HTTPS, and it can't reach localhost directly, so local testing needs a public HTTPS tunnel:

const RETURN_URL = 'https://your-tunnel-subdomain.ngrok-free.dev/payment-callback';

ngrok's free tier assigns a new random domain every time you restart the tunnel — which means re-whitelisting with PayWay's team every time, too. A paid ngrok static domain (or your own domain) avoids that churn.

5. Beginner Pitfalls

  • A callback that never arrives, with no error anywhere, almost always means an un-whitelisted domain — not a bug in your handler. Check the whitelist before debugging your code.
  • ngrok's free-tier domain changes on every restart. If callbacks that used to work stop arriving, check whether your tunnel domain changed and needs re-whitelisting.
  • Logging the callback body is fine for a sandbox exercise, but shipping that as "done" skips signature verification and idempotency — both real gaps, not stylistic choices. See Part 6 for what's still missing.

ទិញកាហ្វេជូនខ្ញុំ

ចូលចិត្តមេរៀននេះមែនទេ? សូមពិចារណាទិញកាហ្វេជូនខ្ញុំមួយកែវ ដើម្បីគាំទ្រការបង្កើតមាតិកាឥតគិតថ្លៃបន្ថែមទៀត!