Skip to content
upınow

Embedded QR widget

Embedding the UPINOW QR widget on your own checkout page, its options, and how status polling works.

On this page

Keep the customer on your own page by embedding the QR widget instead of redirecting to the hosted pay page. Add a container and the script anywhere on your checkout page:

Embed widget (HTML)
<div id="upinow-pay"></div>
<script src="https://app.upinow.in/embed/upinow.js"></script>
<script>
  UPINOW.mount("#upinow-pay", {
    // Your server creates the order with your API key (POST /api/v1/orders) and returns its JSON.
    createOrderUrl: "/api/create-order",
    // title: "Pay for your order", // optional; default "Pay with UPI"
    onSuccess: function (order) {
      // Screen update only. Mark the order paid when the signed webhook arrives.
    }
  });
</script>

Options

Option Type Meaning
createOrderUrl string Recommended. Your own server endpoint. It receives POST { amount } and must return the same JSON POST /api/v1/orders returns.
statusUrl string Optional. Your own server endpoint: GET statusUrl + order_id returns the order JSON. Without it the widget reads the order's public status, the same one the hosted pay page reads, so no key is needed in the browser.
apiKey string Your API key, sent as X-API-Key. Testing only; a production page should proxy through createOrderUrl instead so the key never reaches the browser.
origin string Optional. Your UPINOW address, when the script was not loaded from it. The older name gateway still means the same thing.
title string Optional. The heading shown above the amount field. Defaults to "Pay with UPI".
merchantOrderId string Only used with apiKey and no createOrderUrl. Defaults to order_<timestamp>.
successUrl, failureUrl string Only used with apiKey and no createOrderUrl. Default to the current page.
webhookUrl string Only used with apiKey and no createOrderUrl. Defaults to <page origin>/api/webhooks/autoupi; set your own, since that default almost never points at a real endpoint on your server.
customer object Only used with apiKey and no createOrderUrl. Passed straight through to create-order.
paymentAccountId string Optional. Which of your UPI accounts the order is created on. Only used with apiKey and no createOrderUrl, sent as payment_account_id; with createOrderUrl, your own server decides the account when it calls create-order. Leave it out to use your default account.
onSuccess function Called with the order once its status becomes paid. For screen updates only; never mark anything paid here.

The createOrderUrl contract

Your server, not the browser, should hold the API key. createOrderUrl receives a POST with { "amount": ... } and must call POST /api/v1/orders itself (adding merchant_order_id, success_url, failure_url and webhook_url) and return that response as its own JSON body. See the Plain PHP guide's create-order.php for a working example. For a real cart, work out the amount on your own server; never trust an amount the browser sends you.

Status polling

While the QR is shown, the widget checks the order every 2 seconds: statusUrl if you gave one, otherwise the X-API-Key lookup if you gave apiKey, otherwise the order's public status with no key needed. It stops polling once the order is paid or failed, on a 401, 403 or 404 response, and 10 minutes after the order's expiry (a late bank alert can still pay it inside that window).

At your plan's limit, create-order answers 402 plan_limit_reached and the widget shows: "This shop can't take new UPI payments here right now. Please contact the shop." A paused UPI account (402 payment_account_paused, when paymentAccountId names an account beyond your plan's UPI account limit) shows the same friendly line.

Older pages

/embed/panme-pay.js is byte-identical to /embed/upinow.js and window.PanMePay is the same object as window.UPINOW, so a page written against the old name keeps working with no changes.

See the Plain PHP guide for a full create-order.php proxy you can copy.