External Source
This documentation is synced directly from the GitHub Repository.
MMPay Python SDK¶
A Python client library for integrating with the MMPay Payment Gateway. This SDK is a direct port of the official Node.js SDK, providing utilities for payment creation, transaction retrieval, handshake authentication, and callback verification for technical architects and developers.
⬇️ 1. Installation¶
⚙️ 2. Configuration¶
To use the SDK, you need your App ID, Publishable Key, and Secret Key provided by the MyanMyanPay dashboard.
| Parameter | Type | Required | Description |
|---|---|---|---|
| appId | str | Yes | Your unique Application ID. |
| publishableKey | str | Yes | Public key for authentication. |
| secretKey | str | Yes | Private key used for signing requests (HMAC). |
| apiBaseUrl | str | Yes | The base URL for the MMPay API. |
Implementation
from mmpay import MMPaySDK
options = {
"appId": "YOUR_APP_ID",
"publishableKey": "YOUR_PUBLISHABLE_KEY",
"secretKey": "YOUR_SECRET_KEY",
"apiBaseUrl": "https://xxx.myanmyanpay.com"
}
MMPay = MMPaySDK(options)
💳 3. Make Payment¶
Method Signature
Implementation
from mmpay.types import PaymentRequest
try:
pay_payload: PaymentRequest = {
"orderId": "ORD-LIVE-98765",
"amount": 5000,
"callbackUrl": "https://your-site.com/webhook/mmpay",
"customMessage": "Your Custom Message",
"items": [
{
"name": "Premium Subscription",
"amount": 5000,
"quantity": 1
}
]
}
response = MMPay.pay(pay_payload)
print(response.get('qr')) # this is your QR String [EMVCo String]
print(response.get('orderId')) #this is your order ID
print(response.get('transactionRefId')) #this is your QR Reference No
print(response.get('vendorQrRefId')) #this is your QR Reference No
print(response.get('amount')) #this is your requested amount
except Exception as e:
print(e)
Request Body (payload structure)
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
orderId |
string |
Yes | Your generated order ID for the order or system initiating the payment. | "ORD-3983833" |
amount |
number |
Yes | The total transaction amount. | 1500.50 |
callbackUrl |
string |
No | The URL where the payment gateway will send transaction status updates. | "https://yourserver.com/webhook" |
currency |
string |
No | The currency code (e.g., 'MMK'). |
"MMK" |
customMessage |
string |
No | Your Customization String | |
items |
Array<Object> |
No | List of items included in the purchase. | [{name: "Hat", amount: 1000, quantity: 1}] |
Item Object
| Field | Type | Description |
|---|---|---|
name |
string |
The name of the item. |
amount |
number |
The unit price of the item. |
quantity |
number |
The number of units purchased. |
Response Body Code (201)
{
"orderId": "_trx_0012345",
"status": "PENDING",
"vendorQrRefId": "39233043003345",
"transactionRefId": "39233043003345", // This is deprecated - transactionRefId will show only after payment is confirmed
"amount": 2800,
"currency": "MMK",
"qr": "EMVco MMQR String => You_have_to_embed_as_qr_image_yourself"
}
🚀 4. Retrieve Payment Information¶
Method Signature
Implementation
from mmpay.types import PayGetRequest
try:
get_payload: PayGetRequest = {
"orderId": "ORD-SANDBOX-001"
}
response = MMPay.get(get_payload)
print(response)
except Exception as e:
print(e)
Request Body (payload structure)
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
orderId |
string |
Yes | Your generated order ID for the order or system initiating the payment. | "ORD-3983833" |
Response Body Code (200)
{
"orderId": "ORD-111111111",
"appId": "MMP3883483",
"amount": 1000,
"vendor": "KBZPay",
"method": "QR",
"customMessage": "",
"callbackUrl": "",
"callbackUrlAt": "JSDateObject",
"callbackUrlStatus": "SUCCESS",
"status": "SUCCESS", // 'PENDING' | 'SUCCESS' | 'FAILED' | 'REFUNDED' | 'CANCELLED' | 'EXPIRED';
"disbursementId": "289348734939",
"disStatus": "SUCCESS",
"condition": "TOUCHED", // TOUCHED | 'PRISTINE' | 'DIRTY' | 'EXPIRED'
"createdAt": "JSDateObject",
"transactionRefId": "939583046594",
"vendorQrRefId": "48309449034",
"qr": "EMVCo QR String::MMQR Standard",
}
🚀 5. Cancel Payment¶
Method Signature
Implementation
from mmpay.types import PayCancelRequest
try:
cancel_payload: PayGetRequest = {
"orderId": "ORD-SANDBOX-001"
}
response = MMPay.cancel(cancel_payload)
print(response)
except Exception as e:
print(e)
Request Body (payload structure)
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
orderId |
string |
Yes | Your generated order ID for the order or system initiating the payment. | "ORD-3983833" |
Response Body Code (200)
{
"amount": 1000,
"orderId": "ORD-111111111",
"status": "CANCELLED",
"vendorQrRefId": "289348734939",
}
🔐 6. Handling Webhooks¶
When MyanMyanPay sends a callback to your callbackUrl[cite: 1], you must verify the request signature to ensure it is genuine.
When you implement this method, our package automatically process the Hmac verification
Incoming Headers
| Field Name | Type | Required | Description |
|---|---|---|---|
Content-Type |
str |
Yes | application/json |
X-Mmpay-Signature |
str |
Yes | Generated HMAC signature |
X-Mmpay-Nonce |
str |
Yes | Unique nonce string |
Incoming Body
| Field Name | Type | Required | Description |
|---|---|---|---|
| orderId | string |
Yes | Unique identifier for the specific order. |
| amount | number |
Yes | The transaction amount. |
| currency | string |
Yes | The 3-letter currency code (e.g., MMK, USD). |
| vendor | string |
Yes | Identifier for the vendor initiating the request. |
| method | 'QR', 'PIN', 'PWA', 'CARD' |
Yes | Identifier for the method. |
| status | 'PENDING','SUCCESS','FAILED','REFUNDED', 'EXPIRED', 'CANCELLED' |
Yes | Current status of the transaction. |
| condition | 'PRESTINE', 'TOUCHED', 'EXPIRED', 'DIRTY' |
Yes | Used QR Code scan again or not |
| transactionRefId | string |
Yes | The reference ID generated by the payment provider after success payment |
| vendorQrRefId | string |
Yes | The MMQR reference ID generated by the payment provider. |
| callbackUrl | string |
No | Optional URL to receive webhooks or updates. |
| customMessage | string |
No | User provided custom message |
Example Implementation With Flask
from mmpay.client import MMPaySDK
MMPay = MMPaySDK({
'appId': 'your_app_id',
'publishableKey': 'pk_test_12345',
'secretKey': 'your_secret_key',
'apiBaseUrl': 'https://api.myanmyanpay.com'
})
def handle_create(tx):
# if you are using browser plugin MMPay.showPaymentModal()
# verify your source of truth here, you can do with an encrypted message in customMessage or just match the amount of order reqest
# if the amount does not match 'CANCEL' the order immediately, to avoid payload manipulation attacks
# MMPay.cancel( tx.orderId )
print("Created:", tx.get('orderId'))
def handle_success(tx):
print("Success:", tx.get('orderId'))
def handle_fail(tx):
print("Failed:", tx.get('orderId'))
def handle_refund(tx):
print("Refunded:", tx.get('orderId'))
def handle_cancel(tx):
print("Cancelled:", tx.get('orderId'))
def handle_expire(tx):
print("Expired:", tx.get('orderId'))
def handle_heartbeat(tx):
print("Heartbeat:", tx.get('orderId'))
def handle_unknown(tx):
print("Unknown:", tx.get('status'))
def handle_error(error):
print("Error:", error)
MMPay.on_tx_create(handle_create)
MMPay.on_tx_success(handle_success)
MMPay.on_tx_fail(handle_fail)
MMPay.on_tx_refund(handle_refund)
MMPay.on_tx_cancel(handle_cancel)
MMPay.on_tx_expire(handle_expire)
MMPay.on_heartbeat(handle_heartbeat)
MMPay.on('tx:unknown', handle_unknown)
MMPay.on('error', handle_error)
@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')
if not nonce or not signature:
return jsonify({"error": "Missing headers"}), 400
MMPay.listen(payload_str, nonce, signature)
return jsonify({"received": True}), 200
if __name__ == '__main__':
app.run(port=5000)
💡 7. Verify Callback (Manually)¶
When MyanMyanPay sends a callback to your callbackUrl[cite: 1], you must verify the request signature to ensure it is genuine.
Example Implementation With Flask
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 = MMPay.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
💡 8. Error Codes¶
HMac Layer (SERVER Side)
| Code | Description |
|---|---|
KA0001 |
Bearer Token Not Included |
KA0002 |
API Key Not 'LIVE' |
KA0003 |
Signature mismatch |
KA0004 |
Internal Server Error |
KA0005 |
IP Not whitelisted |
429 |
Rate limit hit (1000 req/min) |
JWT Layer (SERVER Side)
| Code | Description |
|---|---|
BA001 |
Btoken nonce token missing |
BA002 |
Btoken nonce mismatch |
Response Codes
| Code | Status | Description |
|---|---|---|
201 |
Created | Transaction initiated successfully. Response contains QR code URL/details. |
401 |
Unauthorized | Invalid or missing Publishable Key. |
400 |
Bad Request | Missing required body fields (validated by schema, if implemented). |
503 |
Service Unavailable | Upstream payment API failed or is unreachable. |
500 |
Internal Server Error | General server error during payment initiation. |
License¶
MIT