JavaScript / TypeScript SDK
TypeScript/JavaScript client library for the QPay V2 API. Uses the native fetch API — works in Node.js 18+ and modern browsers. Automatic camelCase/snake_case conversion between JS and the QPay API.
Installation
npm install qpay-jsOr with other package managers:
yarn add qpay-js
pnpm add qpay-jsConfiguration
From Environment Variables
Set the following variables, then call loadConfigFromEnv():
| Variable | Description |
|---|---|
QPAY_BASE_URL | QPay API base URL (e.g., https://merchant.qpay.mn) |
QPAY_USERNAME | QPay merchant username |
QPAY_PASSWORD | QPay merchant password |
QPAY_INVOICE_CODE | Default invoice code |
QPAY_CALLBACK_URL | Payment callback URL |
import { QPayClient, loadConfigFromEnv } from 'qpay-js';
const client = new QPayClient(loadConfigFromEnv());Manual Configuration
import { QPayClient } from 'qpay-js';
import type { QPayConfig } from 'qpay-js';
const config: QPayConfig = {
baseUrl: 'https://merchant.qpay.mn',
username: 'YOUR_USERNAME',
password: 'YOUR_PASSWORD',
invoiceCode: 'YOUR_INVOICE_CODE',
callbackUrl: 'https://example.com/api/qpay/callback',
};
const client = new QPayClient(config);Quick Start
import { QPayClient, loadConfigFromEnv } from 'qpay-js';
const config = loadConfigFromEnv();
const client = new QPayClient(config);
const invoice = await client.createSimpleInvoice({
invoiceCode: config.invoiceCode,
senderInvoiceNo: 'ORDER-001',
invoiceReceiverCode: 'terminal',
invoiceDescription: 'Payment for Order #001',
amount: 10000,
callbackUrl: config.callbackUrl,
});
console.log(invoice.invoiceId); // "abc123..."
console.log(invoice.qPayShortUrl); // "https://qpay.mn/s/..."
console.log(invoice.qrImage); // base64-encoded QR image
for (const url of invoice.urls) {
console.log(`${url.name}: ${url.link}`);
}Create Invoice
Simple Invoice
const invoice = await client.createSimpleInvoice({
invoiceCode: 'TEST_INVOICE',
senderInvoiceNo: 'ORDER-002',
invoiceReceiverCode: 'terminal',
invoiceDescription: 'Quick payment',
senderBranchCode: 'BRANCH01', // optional
amount: 10000,
callbackUrl: 'https://example.com/api/qpay/callback',
});Full Invoice
const invoice = await client.createInvoice({
invoiceCode: 'TEST_INVOICE',
senderInvoiceNo: 'ORDER-003',
invoiceReceiverCode: 'terminal',
invoiceDescription: 'Detailed invoice',
amount: 100000,
callbackUrl: 'https://example.com/api/qpay/callback',
lines: [
{
lineDescription: 'Product A',
lineQuantity: '2',
lineUnitPrice: '50000',
},
],
});Cancel Invoice
await client.cancelInvoice('invoice-id-here');Check Payment
const result = await client.checkPayment({
objectType: 'INVOICE',
objectId: invoice.invoiceId,
offset: { pageNumber: 1, pageLimit: 10 },
});
if (result.count > 0) {
console.log(`Payment received! Paid: ${result.paidAmount} MNT`);
for (const row of result.rows) {
console.log(` ${row.paymentId}: ${row.paymentStatus} (${row.paymentAmount} ${row.paymentCurrency})`);
}
} else {
console.log('No payment yet');
}List Payments
const result = await client.listPayments({
objectType: 'INVOICE',
objectId: invoice.invoiceId,
startDate: '2024-01-01',
endDate: '2024-12-31',
offset: { pageNumber: 1, pageLimit: 20 },
});
console.log(`Total: ${result.count}`);
for (const item of result.rows) {
console.log(`${item.paymentId} | ${item.paymentDate} | ${item.paymentAmount} ${item.paymentCurrency}`);
}Get details for a single payment:
const detail = await client.getPayment('payment-id-here');
console.log(`Payment ${detail.paymentId}: ${detail.paymentStatus} (${detail.paymentAmount} ${detail.paymentCurrency})`);Webhook Handling
QPay sends a POST request to your callbackUrl when a payment completes. Here is how to handle it in Express:
import express from 'express';
import { QPayClient, loadConfigFromEnv } from 'qpay-js';
const app = express();
app.use(express.json());
const client = new QPayClient(loadConfigFromEnv());
app.post('/api/qpay/callback', async (req, res) => {
const { payment_id } = req.body;
// Verify the payment by calling QPay API
const result = await client.checkPayment({
objectType: 'INVOICE',
objectId: payment_id,
});
if (result.count > 0) {
// Payment verified -- update your order status
console.log(`Payment confirmed: ${payment_id} (${result.paidAmount} MNT)`);
}
res.sendStatus(200);
});Error Handling
All API errors throw a QPayError with structured information:
import { QPayError, isQPayError, ERR_INVOICE_NOT_FOUND, ERR_AUTHENTICATION_FAILED } from 'qpay-js';
try {
await client.createSimpleInvoice(request);
} catch (err) {
if (isQPayError(err)) {
console.log(err.statusCode); // 400, 401, 404, etc.
console.log(err.code); // "INVOICE_NOTFOUND"
console.log(err.message); // "qpay: INVOICE_NOTFOUND - Invoice not found (status 404)"
console.log(err.rawBody); // Raw JSON response body
switch (err.code) {
case ERR_INVOICE_NOT_FOUND:
// Handle missing invoice
break;
case ERR_AUTHENTICATION_FAILED:
// Handle auth failure
break;
}
} else {
// Non-API error (network, etc.)
console.error(err);
}
}Available Error Code Constants
import {
ERR_AUTHENTICATION_FAILED, // "AUTHENTICATION_FAILED"
ERR_INVOICE_NOT_FOUND, // "INVOICE_NOTFOUND"
ERR_INVOICE_PAID, // "INVOICE_PAID"
ERR_INVOICE_ALREADY_CANCELED, // "INVOICE_ALREADY_CANCELED"
ERR_INVOICE_CODE_INVALID, // "INVOICE_CODE_INVALID"
ERR_INVALID_AMOUNT, // "INVALID_AMOUNT"
ERR_PAYMENT_NOT_FOUND, // "PAYMENT_NOTFOUND"
ERR_PAYMENT_ALREADY_CANCELED, // "PAYMENT_ALREADY_CANCELED"
ERR_PERMISSION_DENIED, // "PERMISSION_DENIED"
// ... and many more
} from 'qpay-js';Browser Usage
This library works in modern browsers that support the fetch API. Use manual configuration instead of loadConfigFromEnv():
<script type="module">
import { QPayClient } from 'qpay-js';
const client = new QPayClient({
baseUrl: 'https://merchant.qpay.mn',
username: 'YOUR_USERNAME',
password: 'YOUR_PASSWORD',
invoiceCode: 'YOUR_INVOICE_CODE',
callbackUrl: 'https://example.com/callback',
});
const invoice = await client.createSimpleInvoice({
invoiceCode: 'YOUR_CODE',
senderInvoiceNo: 'WEB-001',
invoiceReceiverCode: 'terminal',
invoiceDescription: 'Web payment',
amount: 5000,
callbackUrl: 'https://example.com/callback',
});
document.getElementById('qr').src = `data:image/png;base64,${invoice.qrImage}`;
</script>API Reference
| Method | Description | Returns |
|---|---|---|
new QPayClient(config) | Create a new client | QPayClient |
getToken() | Authenticate and return a token pair | Promise<TokenResponse> |
refreshToken() | Refresh the current access token | Promise<TokenResponse> |
createInvoice(req) | Create a detailed invoice | Promise<InvoiceResponse> |
createSimpleInvoice(req) | Create a simple invoice | Promise<InvoiceResponse> |
createEbarimtInvoice(req) | Create an invoice with ebarimt | Promise<InvoiceResponse> |
cancelInvoice(invoiceId) | Cancel an invoice by ID | Promise<void> |
getPayment(paymentId) | Get payment details by ID | Promise<PaymentDetail> |
checkPayment(req) | Check if a payment has been made | Promise<PaymentCheckResponse> |
listPayments(req) | List payments with filters | Promise<PaymentListResponse> |
cancelPayment(paymentId, req?) | Cancel a card payment | Promise<void> |
refundPayment(paymentId, req?) | Refund a card payment | Promise<void> |
createEbarimt(req) | Create an electronic tax receipt | Promise<EbarimtResponse> |
cancelEbarimt(paymentId) | Cancel an ebarimt by payment ID | Promise<EbarimtResponse> |
Links
- npm: npmjs.com/package/qpay-js
- GitHub: github.com/qpay-sdk/qpay-js
Last updated on