Home
The Developer-First MMQR Engine¶
Generate dynamic Myanmar QR codes in milliseconds.
Built for high-velocity engineering teams who need simple, stateless payment integration without the banking bureaucracy.
Get API Keys View API Reference
Integrate in 30 Seconds¶
Myan Myan Pay provides a RESTful JSON API that just works.
const { MMPaySDK } = require('mmpay-node-sdk');
const MMPay = new MMPaySDK({
appId: "MMxxxxxxx",
publishableKey: "pk_test_abcxxxxx",
secretKey: "sk_test_abcxxxxx",
apiBaseUrl: "https://xxxxxx"
})
// async
await MMPay.pay({ orderId, amount, items })
// sync
MMPay.pay({ orderId, amount, items })
.then((response) => {
console.log(response)
}).catch((error) => {
console.log(error)
})
import { MMPaySDK } from 'mmpay-node-sdk';
const MMPay = new MMPaySDK({
appId: "MMxxxxxxx",
publishableKey: "pk_test_abcxxxxx",
secretKey: "sk_test_abcxxxxx",
apiBaseUrl: "https://xxxxxx"
})
// async
await MMPay.pay({ orderId, amount, items })
// sync
MMPay.pay({ orderId, amount, items })
.then((response) => {
console.log(response)
}).catch((error) => {
console.log(error)
})
from mmpay import MMPaySDK
# Initialize the SDK
options = {
"appId": "YOUR_APP_ID",
"publishableKey": "YOUR_PUBLISHABLE_KEY",
"secretKey": "YOUR_SECRET_KEY",
"apiBaseUrl": "[https://xxx.myanmyanpay.com](https://xxx.myanmyanpay.com)" # Replace with actual API Base URL [ Register With Us]
}
sdk = MMPaySDK(options)
payment_request = {
"orderId": "ORD-SANDBOX-001",
"amount": 5000, # Amount in minor units (e.g., cents) or as required
"callbackUrl": "[https://your-site.com/webhook/mmpay](https://your-site.com/webhook/mmpay)",
"items": [
{
"name": "Premium Subscription",
"amount": 5000,
"quantity": 1
}
]
}
response = sdk.sandbox_pay(payment_request)
<?php
use MMPay\MMPay;
$options = [
'appId' => 'YOUR_APP_ID',
'publishableKey' => 'YOUR_PUBLISHABLE_KEY',
'secretKey' => 'YOUR_SECRET_KEY',
'apiBaseUrl' => '[https://api.mmpay.com](https://api.mmpay.com)'
];
$sdk = new MMPay($options);
$params = [
'orderId' => 'ORD-LIVE-888',
'amount' => 10000,
'items' => [
['name' => 'E-Commerce Item', 'amount' => 10000, 'quantity' => 1]
]
];
$response = $sdk->pay($params);
?php>
import com.mmpay.sdk.MMPaySDK;
import com.mmpay.sdk.SDKOptions;
import com.mmpay.sdk.model.PaymentRequest;
import com.mmpay.sdk.model.Item;
import java.util.List;
import java.util.ArrayList;
SDKOptions options = new SDKOptions(
"YOUR_APP_ID",
"YOUR_PUBLISHABLE_KEY",
"YOUR_SECRET_KEY",
"[https://api.mmpay.com](https://api.mmpay.com)"
);
MMPaySDK sdk = new MMPaySDK(options);
try {
PaymentRequest request = new PaymentRequest();
request.orderId = "ORD-SANDBOX-" + System.currentTimeMillis();
request.amount = 5000;
request.currency = "MMK";
request.callbackUrl = "[https://yoursite.com/webhook](https://yoursite.com/webhook)";
// Add Items
request.items = new ArrayList<>();
request.items.add(new Item("Premium Plan", 5000, 1));
Map<String, Object> response = sdk.pay(request);
System.out.println("Response: " + response);
} catch (Exception e) {
e.printStackTrace();
}
// Express.JS Example
app.post("/webhooks/mmpay", async (req, res) => {
const incomingSignature = req.headers('x-mmpay-signature');
const incomingNonce = req.headers('x-mmpay-nonce');
const { payloadString } = req.body;
const cbResponse = await MMPayInstance.verifyCb(payloadString, incomingNonce, incomingSignature );
if (cbResponse) {
const parsedPayload = JSON.parse(payloadString);
if (parsedPayload.status === 'SUCCESS') {
// SUCCESS LOGIC HERE
}
if (parsedPayload.status !== 'SUCCESS') {
// NOT SUCCESS LOGIC HERE
}
}
if (!cbResponse) {
return res.status(500).json({ error: 'Callback Verification Fail' });
}
res.status(200).json({ message: "Success" });
});
// FastifyJS Example
interface MMPayIncomingCallbackScheme {
orderId: string;
amount: number;
currency: string;
vendor: string;
status: 'PENDING' | 'SUCCESS' | 'FAILED' | 'REFUNDED';
transactionRefId: string;
callbackUrl?: string;
}
fastify.post('/webhooks/mmpay', async (request: FastifyRequest<{Body: MMPayIncomingCallbackScheme}>, reply: FastifyReply) => {
const incomingSignature = request.headers['x-mmpay-signature'] as string;
const incomingNonce = request.headers['x-mmpay-nonce'] as string;
const payload = request.body as MMPayIncomingCallbackScheme;
const payloadString = JSON.stringify(payload);
const cbResult = await fastify.mmpay.verifyProductionCallBack({
payloadString: payloadString,
nonce: incomingNonce,
signature: incomingSignature
});
if (cbResult) {
if (payload.status === "SUCCESS") {
}
if (payload.status === 'FAILED') {
};
reply.code(200).send({message: "Callback Processed Successfully"});
}
if (!cbResult) {
reply.code(200).send({message: "Callback Verification Failed"});
}
});
# Flask Framwork Example
from flask import request
@app.route('/webhooks/mmpay', methods=['POST'])
def mmpay_webhook():
payload_str = request.data.decode('utf-8')
nonce = request.headers.get('X-Mmpay-Nonce')
signature = request.headers.get('X-Mmpay-Signature')
try:
is_valid = sdk.verify_cb(payload_str, nonce, signature)
if is_valid:
return "Verified", 200
else:
return "Invalid Signature", 400
except ValueError as e:
return str(e), 400
// Controller File Laravel Example
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use MMPay\MMPay; // Import your package
class PaymentCallbackController extends Controller
{
public function handle(Request $request)
{
$mmpay = new MMPay([
'appId' => env('MMPAY_APP_ID'),
'publishableKey' => env('MMPAY_PUBLISHABLE_KEY'),
'secretKey' => env('MMPAY_SECRET_KEY'),
'apiBaseUrl' => env('MMPAY_API_URL'),
]);
$rawPayload = $request->getContent();
$nonce = $request->header('X-Mmpay-Nonce');
$signature = $request->header('X-Mmpay-Signature');
Log::info('MMPay Callback Received', [
'nonce' => $nonce,
'signature' => $signature
]);
$isValid = $mmpay->verifyCb($rawPayload, $nonce, $signature);
if (!$isValid) {
Log::error('MMPay Signature Verification Failed');
return response()->json(['message' => 'Invalid signature'], 403);
}
$data = json_decode($rawPayload, true);
// ---------------------------------------------------
// TODO: Add your business logic here
// ---------------------------------------------------
// Example:
// $order = Order::where('order_id', $data['orderId'])->first();
// if ($data['status'] === 'PAID') {
// $order->update(['status' => 'completed']);
// }
// ---------------------------------------------------
return response()->json(['status' => 'success']);
}
}
// Example in a Spring Boot Controller
@PostMapping("/webhook")
public ResponseEntity<String> handleWebhook(
@RequestBody String payload,
@RequestHeader("X-Mmpay-Nonce") String nonce,
@RequestHeader("X-Mmpay-Signature") String signature
) {
boolean isValid = sdk.verifyCb(payload, nonce, signature);
if (isValid) {
// ✅ Process order
return ResponseEntity.ok("Verified");
} else {
// ❌ Invalid signature
return ResponseEntity.status(400).body("Invalid Signature");
}
}
Express JS Framwork Usage Full Example¶
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const PORT = process.env.PORT || 3000;
app.use(bodyParser.json());
const { MMPaySDK } = require('mmpay-node-sdk');
const MMPay = new MMPaySDK({
appId: "MMxxxxxxx",
publishableKey: "pk_test_abcxxxxx",
secretKey: "sk_test_abcxxxxx",
apiBaseUrl: "https://xxxxxx"
})
app.post("/create-order", async (req, res) => {
const { amount, items } = req.body;
const orderId = ''; // GET YOUR ORDER ID FROM YOUR BIZ LOGIC
const payload = {
orderId: 'ORD-199399933',
amount: 5000,
items: [
{ name: "Pencil", amount: 5000, quantity: 1 }
],
customMessage: '', // max 150 char string
callbackUrl: 'https://abcdef/callback' // [optional] overrides default callbackURL
}
let payResponse = await MMPay.pay(payload);
res.status(200).json(payResponse);
});
// Validating Callback
app.post("/callback", async (req, res) => {
const incomingSignature = req.headers('x-mmpay-signature');
const incomingNonce = req.headers('x-mmpay-nonce');
const payload = request.body;
const { payloadString } = req.body;
const cbResponse = await MMPay.verifyCb(payloadString, incomingNonce, incomingSignature );
if (cbResponse) {
if (payload.status === "SUCCESS" && payload.condition === "PRISTINE") {
}
if (payload.status === 'FAILED' && payload.condition === "PRISTINE") {
};
if (payload.status === 'REFUNDED' && payload.condition === "PRISTINE") {
};
res.status(200).json({ message: "Success" });
}
if (!cbResponse) {
return res.status(500).json({ error: 'Callback Verification Fail' });
}
});
app.listen(PORT, () => console.log(`Server is running on port ${PORT}`));
Plugins¶
We Love Typescript, so here are our favourite framework plugins implementations
FastifyJS With Plugin Usage Full Example (Fast)¶
// server.ts
import {mmpayPlugin} from './plugins/mmpayPlugin';
interface MMPayIncomingCallbackScheme {
orderId: string;
amount: number;
method: string;
currency: string;
vendor: string;
status: 'PENDING' | 'SUCCESS' | 'FAILED' | 'REFUNDED';
condition: 'PRISTINE' | 'TOUCHED' | 'EXPIRED';
transactionRefId: string;
callbackUrl?: string;
customMessage?: string;
}
const fastify: FastifyInstance = Fastify({ logger: true });
await fastify.register(mmpayPlugin, {
appId: process.env.MMPAY_APP_ID!,
uatPubKey: process.env.MMPAY_UAT_PUBKEY!,
uatSecKey: process.env.MMPAY_UAT_SECKEY!,
prdPubKey: process.env.MMPAY_PRD_PUBKEY!,
prdSecKey: process.env.MMPAY_PRD_SECKEY!,
});
fastify.post('/create-order', async (request: FastifyRequest, reply: FastifyReply) => {
const { amount, orderId, items, customMessage } = body;
const payResponse = await fastify.mmpay.createProductionPayment({ amount, orderId, items, customMessage });
})
fastify.post('/webhooks/mmpay', async (request: FastifyRequest<{Body: any}>, reply: FastifyReply) => {
const incomingSignature = request.headers['x-mmpay-signature'] as string;
const incomingNonce = request.headers['x-mmpay-nonce'] as string;
const payload = request.body as MMPayIncomingCallbackScheme;
const payloadString = JSON.stringify(payload);
const cbResult = await fastify.mmpay.verifyProductionCallBack({
payloadString: payloadString,
nonce: incomingNonce,
signature: incomingSignature
});
if (cbResult) {
if (payload.status === "SUCCESS" && payload.condition === "PRISTINE") {
}
if (payload.status === 'FAILED' && payload.condition === "PRISTINE") {
};
if (payload.status === 'REFUNDED' && payload.condition === "PRISTINE") {
};
reply.code(200).send({message: "Callback Processed Successfully"});
}
if (!cbResult) {
reply.code(200).send({message: "Callback Verification Failed"});
}
});
// plguins/mmpayPlugin.ts
/**
* MMpay FastifyJS Plugin
* @author [NawIng]
* @organization [MyanMyanPay]
*/
import {FastifyInstance, FastifyPluginAsync} from 'fastify';
import fastifyPlugin from 'fastify-plugin';
import {MMPaySDK} from 'mmpay-node-sdk';
/**
* @IOrderedItem
*/
interface IOrderedItem {
name: string;
quantity: number;
amount: number;
}
/**
* @CreatePaymentRequest
*/
export interface CreatePaymentRequest {
amount: number;
orderId: string;
items?: IOrderedItem[];
customMessage?: string;
}
/**
* @PaymentCreateResponse
*/
export interface PaymentCreateResponse {
orderId: string;
amount: number;
currency?: string;
transactionRefId?: string;
qr: string;
}
/**
* @Callback
*/
export interface CallbackEncoded {
payloadString: string;
nonce: string;
signature: string;
}
/**
* @fastify
*/
declare module 'fastify' {
interface FastifyInstance {
mmpay: {
createSandboxPayment: (request: CreatePaymentRequest) => Promise<PaymentCreateResponse>;
verifySandboxCallBack: (request: CallbackEncoded) => Promise<boolean>;
createProductionPayment: (request: CreatePaymentRequest) => Promise<PaymentCreateResponse>;
verifyProductionCallBack: (request: CallbackEncoded) => Promise<boolean>;
};
}
}
/**
* @MMPayPluginOptions
*/
interface MMPayPluginOptions {
appId: string;
uatPubKey: string;
uatSecKey: string;
prdPubKey: string;
prdSecKey: string;
}
const mmpayPlugin: FastifyPluginAsync<MMPayPluginOptions> = fastifyPlugin(async (fastify: FastifyInstance, options: MMPayPluginOptions) => {
const SandBoxMMPay = MMPaySDK({
appId: options.appId,
publishableKey: options.uatPubKey,
secretKey: options.uatSecKey,
apiBaseUrl: 'https://xxx.myanmyanpay.com' // Ask Our Team
});
const ProductionMMPay = MMPaySDK({
appId: options.appId,
publishableKey: options.prdPubKey,
secretKey: options.prdSecKey,
apiBaseUrl: 'https://xxx.myanmyanpay.com' // Ask Our Team
});
/**
* createSandboxPayment
* @param {CreatePaymentRequest} params
* @returns {Promise<PaymentCreateResponse>}
*/
const createSandboxPayment = async (params: CreatePaymentRequest): Promise<PaymentCreateResponse> => {
let options = {
orderId: params.orderId,
currency: 'MMK',
amount: params.amount,
items: params.items,
customMessage: params.customMessage,
}
return await SandBoxMMPay.sandboxPay(options);
}
/**
* verifySandboxCallBack
* @param {CallbackEncoded} params
* @param {string} params.nonce
* @param {string} params.signature
* @returns {Promise<boolean>}
*/
const verifySandboxCallBack = async (params: CallbackEncoded): Promise<boolean> => {
return await SandBoxMMPay.verifyCb(params.payloadString, params.nonce, params.signature);
};
/**
* createProductionPayment
* @param {CreatePaymentRequest} params
* @returns {Promise<PaymentCreateResponse>}
*/
const createProductionPayment = async (params: CreatePaymentRequest): Promise<PaymentCreateResponse> => {
let options = {
orderId: params.orderId,
currency: 'MMK',
amount: params.amount,
items: params.items,
customMessage: params.customMessage,
}
return await ProductionMMPay.pay(options);
};
/**
* verifyProductionCallBack
* @param {CallbackEncoded} params
* @param {string} params.nonce
* @param {string} params.signature
* @returns {Promise<boolean>}
*/
const verifyProductionCallBack = async (params: CallbackEncoded): Promise<boolean> => {
return await ProductionMMPay.verifyCb(params.payloadString, params.nonce, params.signature);
};
/**
* @mmpay
*/
fastify.decorate('mmpay', {
createSandboxPayment,
verifySandboxCallBack,
createProductionPayment,
verifyProductionCallBack
});
});
export {mmpayPlugin};
ElysiaJS With Plugin Usage Full Example (Bun Native - Extremely Fast)¶
// server.ts
//usage example
import {Elysia} from 'elysia';
import {mmpayPlugin} from './plugins/mmpayPlugin';
interface MMPayIncomingCallbackScheme {
orderId: string;
amount: number;
method: string;
currency: string;
vendor: string;
status: 'PENDING' | 'SUCCESS' | 'FAILED' | 'REFUNDED';
condition: 'PRISTINE' | 'TOUCHED' | 'EXPIRED';
transactionRefId: string;
callbackUrl?: string;
customMessage?: string;
}
const app = new Elysia()
.use(mmpayPlugin)
.post('/create-order', async ({body, mmpay}) => {
const { amount, orderId, items } = body;
await mmpay.createProductionPayment(amount, orderid, items)
})
.post('/create-order-sandbox', async ({body, mmpay}) => {
const { amount, orderId, items } = body;
await mmpay.createSandboxPayment(amount, orderid, items)
})
.post('/webhooks/mmpay', async ({body, headers, mmpay}) => {
const incomingSignature = headers['x-mmpay-signature'] as string;
const incomingNonce = headers['x-mmpay-nonce'] as string;
const payload = body as MMPayIncomingCallbackScheme;
const payloadString = JSON.stringify(payload);
const cbResult = await mmpay.verifyProductionCallback({
payloadString: payloadString,
nonce: incomingNonce,
signature: incomingSignature
});
if (cbResult) {
if (payload.status === "SUCCESS" && payload.condition === "PRISTINE") {
}
if (payload.status === 'FAILED' && payload.condition === "PRISTINE") {
};
if (payload.status === 'REFUNDED' && payload.condition === "PRISTINE") {
};
reply.code(200).send({message: "Callback Processed Successfully"});
}
if (!cbResult) {
reply.code(200).send({message: "Callback Verification Failed"});
}
})
.post('/webhooks/mmpay-sandbox', async ({body, headers, mmpay}) => {
const incomingSignature = headers['x-mmpay-signature'] as string;
const incomingNonce = headers['x-mmpay-nonce'] as string;
const payload = body as MMPayIncomingCallbackScheme;
const payloadString = JSON.stringify(payload);
const cbResult = await mmpay.verifySandboxCallback({
payloadString: payloadString,
nonce: incomingNonce,
signature: incomingSignature
});
if (cbResult) {
if (payload.status === "SUCCESS" && payload.condition === "PRISTINE") {
}
if (payload.status === 'FAILED' && payload.condition === "PRISTINE") {
};
if (payload.status === 'REFUNDED' && payload.condition === "PRISTINE") {
};
reply.code(200).send({message: "Callback Processed Successfully"});
}
if (!cbResult) {
reply.code(200).send({message: "Callback Verification Failed"});
}
})
// plguins/mmpayPlugin.ts
/**
* MMpay ElysiaJS Plugin
* @author [NawIng]
* @organization [MyanMyanPay]
*/
import {Elysia} from 'elysia';
import {MMPaySDK} from 'mmpay-node-sdk';
const SandboxMMPay = MMPaySDK({
appId: process.env.SBX_MMPAY_APP_ID!,
publishableKey: process.env.SBX_MMPAY_PUB_KEY!,
secretKey: process.env.SBX_MMPAY_SEC_KEY!,
apiBaseUrl: 'https://xxx.myanmyanpay.com', // Ask Our Team
});
const ProductionMMPay = MMPaySDK({
appId: process.env.PDX_MMPAY_APP_ID!,
publishableKey: process.env.PDX_MMPAY_PUB_KEY!,
secretKey: process.env.PDX_MMPAY_SEC_KEY!,
apiBaseUrl: 'https://xxx.myanmyanpay.com', // Ask Our Team
});
/**
* @Callback
*/
export interface CallbackEncoded {
payloadString: string;
nonce: string;
signature: string;
}
/**
* @PaymentCreateResponse
*/
export interface PaymentCreateResponse {
orderId: string;
amount: number;
currency?: string;
transactionRefId?: string;
qr: string;
}
/**
* @mmpayPlugin
*/
export const mmpayPlugin = new Elysia({name: 'plugin.mmpay'})
.decorate('mmpay', {
/**
* createSandboxPayment
* @param {string} orderId
* @param {number} amount
* @param {string} customMessage
* @param {any[]} items
* @returns
*/
async createSandboxPayment(orderId: string, amount: number, customMessage: string, items: any ): Promise <PaymentCreateResponse> {
return await SandboxMMPay.sandboxPay({
amount,
orderId,
customMessage,
items,
});
},
/**
* verifySandboxCallback
* @param orderId
* @param amount
* @returns
*/
async verifySandboxCallback(params: CallbackEncoded): Promise<boolean> {
return await SandboxMMPay.verifyCb(params.payloadString, params.nonce, params.signature);
},
/**
* createProductionPayment
* @param {string} orderId
* @param {number} amount
* @param {any[]} items
* @returns
*/
async createProductionPayment(orderId: string, amount: number, customMessage: string, items: any): Promise <PaymentCreateResponse> {
return await ProductionMMPay.pay({
amount,
orderId,
customMessage,
items,
});
},
/**
* verifyProductionCallback
* @param {CallbackEncoded} params
* @param {string} params.nonce
* @param {string} params.signature
* @returns {Promise<boolean>}
*/
async verifyProductionCallback(params: CallbackEncoded): Promise<boolean> {
return await ProductionMMPay.verifyCb(params.payloadString, params.nonce, params.signature);
}
});
Why Developers Choose Us¶
-
Sub-Millisecond Latency
Our edge-cached generation engine creates MMQR strings faster than you can render the DOM. No waiting for upstream banking handshakes.
-
Stateless & Secure
We simply translate your payment intent into a valid, scannable MMQR string compatible with KBZPay, Wave, and CB.
-
Type-Safe SDKs
First-class support for TypeScript. Autocomplete for every parameter. If it compiles, it works.