Getting started with the panel, plus the full REST API reference.
Create an account with email + password. An API key is generated for you automatically.
Add your Paytm Business, FamPay, BharatPe or custom UPI account once. Credentials are stored securely and only used server-side.
From the panel or the API. You get an order ID and a public pay link like /pay/<token> — share it and the payer sees a UPI QR plus app intent buttons.
The pay page auto-polls every 2 seconds for 10 minutes. Successful payments settle instantly; unpaid links expire cleanly. One transaction record per order.
Every request is authenticated with your API key, sent in the x-api-key header. You can also send it as Authorization: Bearer <key> or as a user_token body field.
Create and rotate keys on the API keys page. Every key carries a scope that decides which merchant accounts it can charge: All merchants (rotates across everything), Provider (rotates inside one provider) or Account (one fixed account). Each key also carries the payment page template its links use. Because routing and template live on the key, order requests only send the amount and customer details. Keep keys server-side — they can create orders on your account.
Base URL
https://mxpay.vip
Fallback Base URL (if your host can't reach the custom domain)
https://paytmbs.lovable.app
Header
x-api-key: <your_api_key>
Content-Type: application/jsonBoth hosts serve the same API. If your server's outbound connection to mxpay.vip times out (common on shared hosting behind restrictive firewalls), retry the same request against paytmbs.lovable.app. The PHP kit does this automatically.
You can connect many accounts — ten Paytm Business accounts, a couple of FamPay accounts, and so on. When an order is created, BlackPay picks exactly one of them to collect the money. You control that choice when you create the API key — the request body never carries routing fields.
Create a key with scope All merchants — every active account, across every provider, is eligible. One is picked by weighted random: an account with weight 3 receives roughly three times the traffic of a weight 1 account. Weights are set per account on the Merchants page.
curl -X POST https://mxpay.vip/api/public/v1/order/create \
-H "x-api-key: $ALL_MERCHANTS_KEY" -H "Content-Type: application/json" \
-d '{ "amount": 149.5 }'Create a Provider-scoped key and pick the provider in the form. Rotation still happens, but only among that provider's active accounts — useful when you want all traffic on Paytm Business while still spreading it over ten UPI IDs.
curl -X POST https://mxpay.vip/api/public/v1/order/create \
-H "x-api-key: $PAYTM_ONLY_KEY" -H "Content-Type: application/json" \
-d '{ "amount": 149.5 }'Create an Account-scoped key and choose the connected account in the form. No rotation — that one account always collects.
curl -X POST https://mxpay.vip/api/public/v1/order/create \
-H "x-api-key: $STORE_NORTH_KEY" -H "Content-Type: application/json" \
-d '{ "amount": 149.5 }'provider, merchant_account_id, account_label and template are no longer read from the request body — if an older integration still sends them they are ignored, not rejected.409.provider, merchant_account_id and account_label, and its “last used” time is stamped so you can audit the spread./api/public/v1/order/createCreates a payment and returns a shareable UPI pay link valid for 10 minutes.
| Field | Type | Description |
|---|---|---|
| amount | number | Required. Amount in INR, greater than 0. |
| customer_mobile | string | Optional. 10-digit customer mobile. |
| redirect_url | string | Optional. Browser redirect after success (order_id & status appended). |
| callback_url | string | Optional. Server-to-server webhook POSTed when the order finishes. |
| remark1 | string | Optional. Your internal reference, shown on the pay page. |
| remark2 | string | Optional. Second free-form note. |
curl -X POST https://mxpay.vip/api/public/v1/order/create \
-H "x-api-key: $PAYHUB_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 149.5,
"customer_mobile": "9876543210",
"remark1": "invoice-1042"
}'{
"status": true,
"data": {
"order_id": "BYTE47121785237322231",
"provider": "PAYTM",
"merchant_account_id": "6f1c9d2e-6f4a-4b3c-9f01-2d0a7c5b8e11",
"account_label": "store-north",
"amount": 149.5,
"template": "template_4",
"payment_url": "https://mxpay.vip/pay/9xKq...",
"link_token": "9xKq...",
"expires_at": "2026-07-29T10:35:00.000Z"
}
}Payment page templates. Every link renders one of ten mobile-first designs. You pick the design when you create the API key: random picks a random enabled design, all rotates through your enabled designs in order, and template_1 …template_10 pin a specific one. Without a choice on the key, the default mode from your Payment page settings applies. The resolved design is returned as template and stays fixed for that link.
/api/public/v1/order/status/api/public/v1/order/status?order_id=...Returns the current state of an order. Poll every 3–5 seconds while the payer is on the pay page; the order settles to a terminal state within 10 minutes.
curl -X POST https://mxpay.vip/api/public/v1/order/status \
-H "x-api-key: $PAYHUB_KEY" \
-H "Content-Type: application/json" \
-d '{ "order_id": "BYTE47121785237322231" }'{
"status": true,
"data": {
"order_id": "BYTE47121785237322231",
"provider": "PAYTM",
"amount": 149.5,
"txn_status": "TXN_SUCCESS",
"utr": "419812345678",
"gateway_txn": "20260729111212800110168...",
"paid_at": "2026-07-29T10:32:11.000Z",
"expires_at": "2026-07-29T10:35:00.000Z",
"payment_url": "https://mxpay.vip/pay/9xKq..."
}
}PENDING — awaiting payment; keep polling.TXN_SUCCESS — money received and amount matched. Terminal.FAILED — the 5-minute window closed without a verified credit. Terminal.EXPIRED — link no longer usable. Terminal.Keep the customer on your own site: create the order from your server, then open the payment page in a popup window. The popup reports the result back to your page and closes itself.
<script src="https://mxpay.vip/checkout.js"></script>
<button id="pay">Pay</button>
<script>
pay.onclick = async () => {
// your own server creates the order and returns link_token
const r = await fetch('/create-order-ajax.php', { method: 'POST', body: new URLSearchParams({ amount: '500' }) });
const d = await r.json();
BlackPay.checkout({
token: d.link_token,
onSuccess: (res) => location.href = '/return.php?order_id=' + res.order_id,
onFailure: (res) => alert('Payment failed: ' + res.status),
onClose: () => console.log('popup closed'),
});
};
</script>token — the link_token from the create-order response (or pass payment_url instead)mode: 'redirect' — open the payment page in the same tab instead of a popuponSuccess / onFailure / onClose — callbacks; BlackPay.close() closes the popup manuallyMessage posted to your page on a terminal state:
{ "source": "blackpay", "event": "payment", "status": "TXN_SUCCESS", "order_id": "BYTE...", "amount": 500 }If the browser blocks popups, the SDK shows a "Continue to payment" link instead. The onSuccess payload is advisory — always confirm with /api/public/v1/order/status or the signed callback before delivering.
Ready-made PHP files to plug this gateway into any PHP website — a cURL client, a checkout form, a return page and a JSON polling endpoint.
config.php — base URL, API key, return URLBlackPay.php — client with createOrder / orderStatus / isPaidcheckout.php — amount form that redirects to the payment pagepopup-checkout.php + create-order-ajax.php — self-checkout popup examplereturn.php — verifies the final status server-sidestatus-api.php — JSON endpoint for AJAX pollingrequire 'config.php';
require 'BlackPay.php';
$bp = new BlackPay(BLACKPAY_BASE_URL, BLACKPAY_API_KEY);
$order = $bp->createOrder(149.50, '9999999999', BLACKPAY_RETURN_URL);
header('Location: ' . $order['payment_url']);
// later, after the payer returns:
if ($bp->isPaid($order['order_id'])) { /* deliver the goods */ }Only mark an order paid when the server-side status is TXN_SUCCESS. Never put the API key in browser JavaScript.
A Freecharge merchant account can confirm payments automatically by signing in with the account's mobile number and an OTP. Open Merchants → Freecharge → Edit, save the account, then enter the mobile number and the OTP you receive.
How the login works
How a payment is matched
While an order is pending, recent Freecharge transactions are read and a credit is accepted when its Comments field contains the order reference, or when the amount matches exactly inside the order window. On a match the order becomes TXN_SUCCESS with the UPI reference stored as the UTR.
Session expiry
Freecharge sessions cannot be refreshed silently. When a session stops working the account is marked expired, admins are alerted, and verification pauses until you log in again with a new OTP. Orders keep working meanwhile and can still be verified manually.
OTPs, cookies and CSRF tokens are never logged; session cookies are stored encrypted and are never returned to the browser.
Errors return a non-2xx code with { "status": false, "error": "..." }.
401 — missing, invalid or expired API key.404 — order not found on your account.409 — that merchant is not connected, or FamPay needs Gmail linked.422 — invalid request body.