Inline / embed checkout

Keep customers on your site with an embeddable MoMo checkout modal — same hosted checkout, without a full-page redirect.

Choose how checkout opens

ParameterTypeDescription
embed: truemodalRecommended for “pay on your site”. Opens an overlay + iframe of /pay/… with ?embed=1.
(default)redirectNavigates the current window to authorization_url. Simplest path — see Redirect checkout.
popup: truewindowOpens a 480×720 popup. Ignored when embed is true. Useful if you cannot use iframes.
Modes
<script src="https://waaguan.com/waaguan-pay.js"></script>
<script>
  var url = data.authorization_url; // from Initialize

  // A) Embed modal on your site (recommended for “stay on page”)
  WaaguanPay.checkout({
    authorizationUrl: url,
    embed: true,
    onSuccess: function (p) { console.log(p.reference); },
    onClose: function () {},
  });

  // B) Full-page redirect (simplest)
  // WaaguanPay.checkout({ authorizationUrl: url });

  // C) Browser popup window
  // WaaguanPay.checkout({ authorizationUrl: url, popup: true });

  // D) Open by reference only (same origin as the script)
  // WaaguanPay.checkout({ reference: "wa-6281126272", embed: true });
</script>

Full example (server + embed)

  1. Your backend calls Initialize with Bearer sk_live_….
  2. Your frontend receives authorization_url and reference (never the secret key).
  3. Call WaaguanPay.checkout({ embed: true, … }.
  4. Customer completes MoMo payment in the modal; the charge becomes paid.
  5. Use onSuccess for UI only. Fulfill after webhook or Verify.
Embed + callbacks
<!-- 1) Load once on your checkout page -->
<script src="https://waaguan.com/waaguan-pay.js"></script>

<script>
  // 2) After your server returns initialize → data.authorization_url
  async function payNow() {
    const res = await fetch("/api/your-backend/create-charge", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ amount: 50, customer_name: "AMA MENSAH" }),
    });
    const { authorization_url, reference } = await res.json();

    WaaguanPay.checkout({
      authorizationUrl: authorization_url,
      embed: true,
      onSuccess: function (payment) {
        // UX only — still verify / wait for webhook before fulfilling
        console.log("paid", payment.reference, payment.status);
        window.location.href = "/orders/thank-you?reference=" + payment.reference;
      },
      onClose: function () {
        // Modal closed (paid or dismissed)
      },
    });
  }

  document.getElementById("pay-btn").addEventListener("click", payNow);
</script>

Script URL

Hosted at https://waaguan.com/waaguan-pay.js. Load it from your Waaguan deployment origin so the helper can resolve checkout URLs and validate origins correctly.

Options reference

ParameterTypeDescription
authorizationUrlstringFull checkout URL from Initialize (recommended). Must be this app’s /pay/… URL.
referencestringAlternative to authorizationUrl. Opens /pay/{reference} on the script origin.
embedbooleanIf true, opens the modal iframe. Adds ?embed=1 to the checkout URL.
popupbooleanIf true (and embed is not set), opens a popup window instead of redirecting.
onSuccessfunctionCalled after charge.success (embed only). Receives { reference, status, event }. UX only.
onClosefunctionCalled when the modal closes — after success or when the user dismisses it (after confirm if payment is still pending).
closeOnBackdropbooleanDefault false. If true, clicking the dimmed backdrop can dismiss (still asks to confirm while payment is pending).

Return value

WaaguanPay.checkout(…) returns { close() }. In embed mode, close() asks for confirmation if payment is still pending (same as the X / Escape). Opening a new embed closes any existing one first.

Success callbacks

In embed mode, when payment is confirmed the checkout page notifies the parent window:

postMessage payload
{
  "source": "waaguan-pay",
  "event": "charge.success",
  "reference": "wa-6281126272",
  "status": "paid"
}
  • waaguan-pay.js listens for source: "waaguan-pay" from the Waaguan origin.
  • On charge.success it shows “Payment successful”, then calls onSuccess and onClose. If the tab was in the background (customer in MoMo), it waits until they return before auto-closing.
  • Closing via X, Escape, or close() only runs onClose (no onSuccess) after the user confirms.
  • callback_url browser redirects are skipped while embedded — use onSuccess plus webhook / Verify instead.
onSuccess(data) argument
{
  "reference": "wa-6281126272",
  "status": "paid",
  "event": "charge.success"
}

Security notes

  • Secret keys never go in waaguan-pay.js or page JS.
  • Only pass authorization_url / referencefrom your server's Initialize response.
  • Prefer HTTPS on your site in production so the modal and iframe load cleanly.

UX tips

  • Prefer embed: true over popup on mobile — popups often die when the customer opens the MoMo app.
  • The embed modal stays open while they send MoMo. Closing X / Escape asks for confirmation. Backdrop click does not dismiss by default (set closeOnBackdrop: true if you want that).
  • Checkout keeps checking in the background when the tab is hidden. Still wire webhooks or Verify — if they leave your site entirely, fulfillment must not depend on the modal.
  • On onClose without success, offer “Try again” with a new Initialize (do not reuse expired references).
  • Branding (template / color) from Dashboard → Checkout applies inside the embed the same as hosted checkout.

Embed vs redirect vs payment links

  • Embed (this page) — stay on your site; best for apps and custom checkouts.
  • Redirect — simplest; full-page /pay/wa-….
  • Payment links — no code; share a URL from the dashboard.