mmpay-python-sdk 0.1.1__tar.gz → 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mmpay_python_sdk-0.1.3/PKG-INFO +268 -0
- mmpay_python_sdk-0.1.3/README.md +243 -0
- {mmpay_python_sdk-0.1.1 → mmpay_python_sdk-0.1.3}/mmpay/client.py +125 -105
- mmpay_python_sdk-0.1.3/mmpay_python_sdk.egg-info/PKG-INFO +268 -0
- {mmpay_python_sdk-0.1.1 → mmpay_python_sdk-0.1.3}/mmpay_python_sdk.egg-info/SOURCES.txt +1 -0
- mmpay_python_sdk-0.1.3/pyproject.toml +3 -0
- mmpay_python_sdk-0.1.3/setup.py +29 -0
- {mmpay_python_sdk-0.1.1 → mmpay_python_sdk-0.1.3}/test/test_sdk.py +2 -2
- mmpay_python_sdk-0.1.1/PKG-INFO +0 -11
- mmpay_python_sdk-0.1.1/README.md +0 -218
- mmpay_python_sdk-0.1.1/mmpay_python_sdk.egg-info/PKG-INFO +0 -11
- mmpay_python_sdk-0.1.1/setup.py +0 -13
- {mmpay_python_sdk-0.1.1 → mmpay_python_sdk-0.1.3}/mmpay/__init__.py +0 -0
- {mmpay_python_sdk-0.1.1 → mmpay_python_sdk-0.1.3}/mmpay_python_sdk.egg-info/dependency_links.txt +0 -0
- {mmpay_python_sdk-0.1.1 → mmpay_python_sdk-0.1.3}/mmpay_python_sdk.egg-info/requires.txt +0 -0
- {mmpay_python_sdk-0.1.1 → mmpay_python_sdk-0.1.3}/mmpay_python_sdk.egg-info/top_level.txt +0 -0
- {mmpay_python_sdk-0.1.1 → mmpay_python_sdk-0.1.3}/setup.cfg +0 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mmpay-python-sdk
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Python SDK for MyanMyanPay
|
|
5
|
+
Home-page: https://github.com/nawing/MMPay-Python-SDK
|
|
6
|
+
Author: Naw Ing
|
|
7
|
+
Author-email: nawing@myanmyanpay.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
12
|
+
Classifier: Topic :: Office/Business :: Financial :: Point-Of-Sale
|
|
13
|
+
Requires-Python: >=3.6
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: requests
|
|
16
|
+
Dynamic: author
|
|
17
|
+
Dynamic: author-email
|
|
18
|
+
Dynamic: classifier
|
|
19
|
+
Dynamic: description
|
|
20
|
+
Dynamic: description-content-type
|
|
21
|
+
Dynamic: home-page
|
|
22
|
+
Dynamic: requires-dist
|
|
23
|
+
Dynamic: requires-python
|
|
24
|
+
Dynamic: summary
|
|
25
|
+
|
|
26
|
+
# MMPay Python SDK
|
|
27
|
+
|
|
28
|
+
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.
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- Sandbox & Production Support: Dedicated methods for both environments.
|
|
33
|
+
- Payment Creation & Retrieval: Endpoints to create payments and fetch transaction statuses.
|
|
34
|
+
- HMAC SHA256 Signing: Automatic signature generation for request integrity.
|
|
35
|
+
- Callback Verification: Utility to verify incoming webhooks from MMPay.
|
|
36
|
+
- Type Definitions: Includes TypedDict definitions for clear payload structuring.
|
|
37
|
+
|
|
38
|
+
## Installation
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install mmpay-python-sdk
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Configuration
|
|
45
|
+
|
|
46
|
+
To use the SDK, you need your App ID, Publishable Key, and Secret Key provided by the MyanMyanPay dashboard.
|
|
47
|
+
|
|
48
|
+
| Parameter | Type | Required | Description |
|
|
49
|
+
| :--- | :--- | :--- | :--- |
|
|
50
|
+
| appId | str | Yes | Your unique Application ID. |
|
|
51
|
+
| publishableKey | str | Yes | Public key for authentication. |
|
|
52
|
+
| secretKey | str | Yes | Private key used for signing requests (HMAC). |
|
|
53
|
+
| apiBaseUrl | str | Yes | The base URL for the MMPay API. |
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from mmpay import MMPaySDK
|
|
58
|
+
|
|
59
|
+
options = {
|
|
60
|
+
"appId": "YOUR_APP_ID",
|
|
61
|
+
"publishableKey": "YOUR_PUBLISHABLE_KEY",
|
|
62
|
+
"secretKey": "YOUR_SECRET_KEY",
|
|
63
|
+
"apiBaseUrl": "https://xxx.myanmyanpay.com"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
sdk = MMPaySDK(options)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Usage
|
|
70
|
+
|
|
71
|
+
### 1. Payment Request Payload
|
|
72
|
+
|
|
73
|
+
Passed to `sdk.pay(params)` or `sdk.sandbox_pay(params)`.
|
|
74
|
+
|
|
75
|
+
| Parameter | Type | Required | Description |
|
|
76
|
+
| :--- | :--- | :--- | :--- |
|
|
77
|
+
| `orderId` | `str` | Yes | Unique identifier for the order (e.g., "ORD-001"). |
|
|
78
|
+
| `amount` | `float` | Yes | Total transaction amount. |
|
|
79
|
+
| `items` | `List[Item]` | No | A list of items included in the order. |
|
|
80
|
+
| `callbackUrl` | `str` | No | URL where the webhook callback will be sent. |
|
|
81
|
+
| `customMessage` | `str` | No | Custom message to be attached to the transaction. |
|
|
82
|
+
|
|
83
|
+
**Item Object**
|
|
84
|
+
|
|
85
|
+
Used inside the `items` list of a Payment Request.
|
|
86
|
+
|
|
87
|
+
| Parameter | Type | Required | Description |
|
|
88
|
+
| :--- | :--- | :--- | :--- |
|
|
89
|
+
| `name` | `str` | Yes | Name of the product/service. |
|
|
90
|
+
| `amount` | `float` | Yes | Price per unit. |
|
|
91
|
+
| `quantity` | `int` | Yes | Quantity of the item. |
|
|
92
|
+
|
|
93
|
+
### 2. Create a Payment
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
try:
|
|
97
|
+
payment_request = {
|
|
98
|
+
"orderId": "ORD-LIVE-98765",
|
|
99
|
+
"amount": 5000,
|
|
100
|
+
"callbackUrl": "https://your-site.com/webhook/mmpay",
|
|
101
|
+
"customMessage": "Your Custom Message",
|
|
102
|
+
"items": [
|
|
103
|
+
{
|
|
104
|
+
"name": "Premium Subscription",
|
|
105
|
+
"amount": 5000,
|
|
106
|
+
"quantity": 1
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
response = sdk.pay(payment_request)
|
|
112
|
+
print(response.get('url'))
|
|
113
|
+
|
|
114
|
+
except Exception as e:
|
|
115
|
+
print(e)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 3. Retrieve a Payment
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
try:
|
|
122
|
+
get_request = {
|
|
123
|
+
"orderId": "ORD-SANDBOX-001"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
response = sdk.get(get_request)
|
|
127
|
+
print(response)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 4. Handling Webhooks
|
|
131
|
+
|
|
132
|
+
When MyanMyanPay sends a callback to your `callbackUrl`[cite: 1], you must verify the request signature to ensure it is genuine.
|
|
133
|
+
When you implement this method, our package automatically process the Hmac verification
|
|
134
|
+
|
|
135
|
+
**Incoming Headers**
|
|
136
|
+
|
|
137
|
+
| Field Name | Type | Required | Description |
|
|
138
|
+
| :--- | :--- | :--- | :--- |
|
|
139
|
+
| `Content-Type` | `str` | Yes | `application/json` |
|
|
140
|
+
| `X-Mmpay-Signature` | `str` | Yes | Generated HMAC signature |
|
|
141
|
+
| `X-Mmpay-Nonce` | `str` | Yes | Unique nonce string |
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
|
|
145
|
+
from mmpay.client import MMPaySDK
|
|
146
|
+
|
|
147
|
+
sdk = MMPaySDK({
|
|
148
|
+
'appId': 'your_app_id',
|
|
149
|
+
'publishableKey': 'pk_test_12345',
|
|
150
|
+
'secretKey': 'your_secret_key',
|
|
151
|
+
'apiBaseUrl': 'https://api.myanmyanpay.com'
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
def handle_create(tx):
|
|
155
|
+
print("Created:", tx.get('orderId'))
|
|
156
|
+
|
|
157
|
+
def handle_success(tx):
|
|
158
|
+
print("Success:", tx.get('orderId'))
|
|
159
|
+
|
|
160
|
+
def handle_fail(tx):
|
|
161
|
+
print("Failed:", tx.get('orderId'))
|
|
162
|
+
|
|
163
|
+
def handle_refund(tx):
|
|
164
|
+
print("Refunded:", tx.get('orderId'))
|
|
165
|
+
|
|
166
|
+
def handle_cancel(tx):
|
|
167
|
+
print("Cancelled:", tx.get('orderId'))
|
|
168
|
+
|
|
169
|
+
def handle_expire(tx):
|
|
170
|
+
print("Expired:", tx.get('orderId'))
|
|
171
|
+
|
|
172
|
+
def handle_heartbeat(tx):
|
|
173
|
+
print("Heartbeat:", tx.get('orderId'))
|
|
174
|
+
|
|
175
|
+
def handle_unknown(tx):
|
|
176
|
+
print("Unknown:", tx.get('status'))
|
|
177
|
+
|
|
178
|
+
def handle_error(error):
|
|
179
|
+
print("Error:", error)
|
|
180
|
+
|
|
181
|
+
sdk.on_tx_create(handle_create)
|
|
182
|
+
sdk.on_tx_success(handle_success)
|
|
183
|
+
sdk.on_tx_fail(handle_fail)
|
|
184
|
+
sdk.on_tx_refund(handle_refund)
|
|
185
|
+
sdk.on_tx_cancel(handle_cancel)
|
|
186
|
+
sdk.on_tx_expire(handle_expire)
|
|
187
|
+
sdk.on_heartbeat(handle_heartbeat)
|
|
188
|
+
sdk.on('tx:unknown', handle_unknown)
|
|
189
|
+
sdk.on('error', handle_error)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
@app.route('/webhooks/mmpay', methods=['POST'])
|
|
193
|
+
def mmpay_webhook():
|
|
194
|
+
payload_str = request.data.decode('utf-8')
|
|
195
|
+
nonce = request.headers.get('X-Mmpay-Nonce')
|
|
196
|
+
signature = request.headers.get('X-Mmpay-Signature')
|
|
197
|
+
|
|
198
|
+
if not nonce or not signature:
|
|
199
|
+
return jsonify({"error": "Missing headers"}), 400
|
|
200
|
+
|
|
201
|
+
sdk.listen(payload_str, nonce, signature)
|
|
202
|
+
|
|
203
|
+
return jsonify({"received": True}), 200
|
|
204
|
+
|
|
205
|
+
if __name__ == '__main__':
|
|
206
|
+
app.run(port=5000)
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### 5. Verify Callback (Manually)
|
|
211
|
+
|
|
212
|
+
When MyanMyanPay sends a callback to your `callbackUrl`[cite: 1], you must verify the request signature to ensure it is genuine.
|
|
213
|
+
|
|
214
|
+
**Incoming Headers**
|
|
215
|
+
|
|
216
|
+
| Field Name | Type | Required | Description |
|
|
217
|
+
| :--- | :--- | :--- | :--- |
|
|
218
|
+
| `Content-Type` | `str` | Yes | `application/json` |
|
|
219
|
+
| `X-Mmpay-Signature` | `str` | Yes | Generated HMAC signature |
|
|
220
|
+
| `X-Mmpay-Nonce` | `str` | Yes | Unique nonce string |
|
|
221
|
+
|
|
222
|
+
**Example Verification (Flask)**
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
from flask import request
|
|
227
|
+
|
|
228
|
+
@app.route('/webhooks/mmpay', methods=['POST'])
|
|
229
|
+
def mmpay_webhook():
|
|
230
|
+
payload_str = request.data.decode('utf-8')
|
|
231
|
+
nonce = request.headers.get('X-Mmpay-Nonce')
|
|
232
|
+
signature = request.headers.get('X-Mmpay-Signature')
|
|
233
|
+
|
|
234
|
+
try:
|
|
235
|
+
is_valid = sdk.verify_cb(payload_str, nonce, signature)
|
|
236
|
+
|
|
237
|
+
if is_valid:
|
|
238
|
+
return "Verified", 200
|
|
239
|
+
else:
|
|
240
|
+
return "Invalid Signature", 400
|
|
241
|
+
|
|
242
|
+
except ValueError as e:
|
|
243
|
+
return str(e), 400
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Error Codes
|
|
247
|
+
|
|
248
|
+
### API Key Layer (SERVER SDK)
|
|
249
|
+
|
|
250
|
+
| Code | Description |
|
|
251
|
+
| :--- | :--- |
|
|
252
|
+
| `KA0001` | Bearer Token Not Included |
|
|
253
|
+
| `KA0002` | API Key Not 'LIVE' |
|
|
254
|
+
| `KA0003` | Signature mismatch |
|
|
255
|
+
| `KA0004` | Internal Server Error |
|
|
256
|
+
| `KA0005` | IP Not whitelisted |
|
|
257
|
+
| `429` | Rate limit hit (1000 req/min) |
|
|
258
|
+
|
|
259
|
+
### JWT Layer (SERVER SDK)
|
|
260
|
+
|
|
261
|
+
| Code | Description |
|
|
262
|
+
| :--- | :--- |
|
|
263
|
+
| `BA001` | `Btoken` nonce token missing |
|
|
264
|
+
| `BA002` | `Btoken` nonce mismatch |
|
|
265
|
+
|
|
266
|
+
## License
|
|
267
|
+
|
|
268
|
+
MIT
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# MMPay Python SDK
|
|
2
|
+
|
|
3
|
+
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.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Sandbox & Production Support: Dedicated methods for both environments.
|
|
8
|
+
- Payment Creation & Retrieval: Endpoints to create payments and fetch transaction statuses.
|
|
9
|
+
- HMAC SHA256 Signing: Automatic signature generation for request integrity.
|
|
10
|
+
- Callback Verification: Utility to verify incoming webhooks from MMPay.
|
|
11
|
+
- Type Definitions: Includes TypedDict definitions for clear payload structuring.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install mmpay-python-sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Configuration
|
|
20
|
+
|
|
21
|
+
To use the SDK, you need your App ID, Publishable Key, and Secret Key provided by the MyanMyanPay dashboard.
|
|
22
|
+
|
|
23
|
+
| Parameter | Type | Required | Description |
|
|
24
|
+
| :--- | :--- | :--- | :--- |
|
|
25
|
+
| appId | str | Yes | Your unique Application ID. |
|
|
26
|
+
| publishableKey | str | Yes | Public key for authentication. |
|
|
27
|
+
| secretKey | str | Yes | Private key used for signing requests (HMAC). |
|
|
28
|
+
| apiBaseUrl | str | Yes | The base URL for the MMPay API. |
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from mmpay import MMPaySDK
|
|
33
|
+
|
|
34
|
+
options = {
|
|
35
|
+
"appId": "YOUR_APP_ID",
|
|
36
|
+
"publishableKey": "YOUR_PUBLISHABLE_KEY",
|
|
37
|
+
"secretKey": "YOUR_SECRET_KEY",
|
|
38
|
+
"apiBaseUrl": "https://xxx.myanmyanpay.com"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
sdk = MMPaySDK(options)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Usage
|
|
45
|
+
|
|
46
|
+
### 1. Payment Request Payload
|
|
47
|
+
|
|
48
|
+
Passed to `sdk.pay(params)` or `sdk.sandbox_pay(params)`.
|
|
49
|
+
|
|
50
|
+
| Parameter | Type | Required | Description |
|
|
51
|
+
| :--- | :--- | :--- | :--- |
|
|
52
|
+
| `orderId` | `str` | Yes | Unique identifier for the order (e.g., "ORD-001"). |
|
|
53
|
+
| `amount` | `float` | Yes | Total transaction amount. |
|
|
54
|
+
| `items` | `List[Item]` | No | A list of items included in the order. |
|
|
55
|
+
| `callbackUrl` | `str` | No | URL where the webhook callback will be sent. |
|
|
56
|
+
| `customMessage` | `str` | No | Custom message to be attached to the transaction. |
|
|
57
|
+
|
|
58
|
+
**Item Object**
|
|
59
|
+
|
|
60
|
+
Used inside the `items` list of a Payment Request.
|
|
61
|
+
|
|
62
|
+
| Parameter | Type | Required | Description |
|
|
63
|
+
| :--- | :--- | :--- | :--- |
|
|
64
|
+
| `name` | `str` | Yes | Name of the product/service. |
|
|
65
|
+
| `amount` | `float` | Yes | Price per unit. |
|
|
66
|
+
| `quantity` | `int` | Yes | Quantity of the item. |
|
|
67
|
+
|
|
68
|
+
### 2. Create a Payment
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
try:
|
|
72
|
+
payment_request = {
|
|
73
|
+
"orderId": "ORD-LIVE-98765",
|
|
74
|
+
"amount": 5000,
|
|
75
|
+
"callbackUrl": "https://your-site.com/webhook/mmpay",
|
|
76
|
+
"customMessage": "Your Custom Message",
|
|
77
|
+
"items": [
|
|
78
|
+
{
|
|
79
|
+
"name": "Premium Subscription",
|
|
80
|
+
"amount": 5000,
|
|
81
|
+
"quantity": 1
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
response = sdk.pay(payment_request)
|
|
87
|
+
print(response.get('url'))
|
|
88
|
+
|
|
89
|
+
except Exception as e:
|
|
90
|
+
print(e)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 3. Retrieve a Payment
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
try:
|
|
97
|
+
get_request = {
|
|
98
|
+
"orderId": "ORD-SANDBOX-001"
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
response = sdk.get(get_request)
|
|
102
|
+
print(response)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 4. Handling Webhooks
|
|
106
|
+
|
|
107
|
+
When MyanMyanPay sends a callback to your `callbackUrl`[cite: 1], you must verify the request signature to ensure it is genuine.
|
|
108
|
+
When you implement this method, our package automatically process the Hmac verification
|
|
109
|
+
|
|
110
|
+
**Incoming Headers**
|
|
111
|
+
|
|
112
|
+
| Field Name | Type | Required | Description |
|
|
113
|
+
| :--- | :--- | :--- | :--- |
|
|
114
|
+
| `Content-Type` | `str` | Yes | `application/json` |
|
|
115
|
+
| `X-Mmpay-Signature` | `str` | Yes | Generated HMAC signature |
|
|
116
|
+
| `X-Mmpay-Nonce` | `str` | Yes | Unique nonce string |
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
|
|
120
|
+
from mmpay.client import MMPaySDK
|
|
121
|
+
|
|
122
|
+
sdk = MMPaySDK({
|
|
123
|
+
'appId': 'your_app_id',
|
|
124
|
+
'publishableKey': 'pk_test_12345',
|
|
125
|
+
'secretKey': 'your_secret_key',
|
|
126
|
+
'apiBaseUrl': 'https://api.myanmyanpay.com'
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
def handle_create(tx):
|
|
130
|
+
print("Created:", tx.get('orderId'))
|
|
131
|
+
|
|
132
|
+
def handle_success(tx):
|
|
133
|
+
print("Success:", tx.get('orderId'))
|
|
134
|
+
|
|
135
|
+
def handle_fail(tx):
|
|
136
|
+
print("Failed:", tx.get('orderId'))
|
|
137
|
+
|
|
138
|
+
def handle_refund(tx):
|
|
139
|
+
print("Refunded:", tx.get('orderId'))
|
|
140
|
+
|
|
141
|
+
def handle_cancel(tx):
|
|
142
|
+
print("Cancelled:", tx.get('orderId'))
|
|
143
|
+
|
|
144
|
+
def handle_expire(tx):
|
|
145
|
+
print("Expired:", tx.get('orderId'))
|
|
146
|
+
|
|
147
|
+
def handle_heartbeat(tx):
|
|
148
|
+
print("Heartbeat:", tx.get('orderId'))
|
|
149
|
+
|
|
150
|
+
def handle_unknown(tx):
|
|
151
|
+
print("Unknown:", tx.get('status'))
|
|
152
|
+
|
|
153
|
+
def handle_error(error):
|
|
154
|
+
print("Error:", error)
|
|
155
|
+
|
|
156
|
+
sdk.on_tx_create(handle_create)
|
|
157
|
+
sdk.on_tx_success(handle_success)
|
|
158
|
+
sdk.on_tx_fail(handle_fail)
|
|
159
|
+
sdk.on_tx_refund(handle_refund)
|
|
160
|
+
sdk.on_tx_cancel(handle_cancel)
|
|
161
|
+
sdk.on_tx_expire(handle_expire)
|
|
162
|
+
sdk.on_heartbeat(handle_heartbeat)
|
|
163
|
+
sdk.on('tx:unknown', handle_unknown)
|
|
164
|
+
sdk.on('error', handle_error)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@app.route('/webhooks/mmpay', methods=['POST'])
|
|
168
|
+
def mmpay_webhook():
|
|
169
|
+
payload_str = request.data.decode('utf-8')
|
|
170
|
+
nonce = request.headers.get('X-Mmpay-Nonce')
|
|
171
|
+
signature = request.headers.get('X-Mmpay-Signature')
|
|
172
|
+
|
|
173
|
+
if not nonce or not signature:
|
|
174
|
+
return jsonify({"error": "Missing headers"}), 400
|
|
175
|
+
|
|
176
|
+
sdk.listen(payload_str, nonce, signature)
|
|
177
|
+
|
|
178
|
+
return jsonify({"received": True}), 200
|
|
179
|
+
|
|
180
|
+
if __name__ == '__main__':
|
|
181
|
+
app.run(port=5000)
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 5. Verify Callback (Manually)
|
|
186
|
+
|
|
187
|
+
When MyanMyanPay sends a callback to your `callbackUrl`[cite: 1], you must verify the request signature to ensure it is genuine.
|
|
188
|
+
|
|
189
|
+
**Incoming Headers**
|
|
190
|
+
|
|
191
|
+
| Field Name | Type | Required | Description |
|
|
192
|
+
| :--- | :--- | :--- | :--- |
|
|
193
|
+
| `Content-Type` | `str` | Yes | `application/json` |
|
|
194
|
+
| `X-Mmpay-Signature` | `str` | Yes | Generated HMAC signature |
|
|
195
|
+
| `X-Mmpay-Nonce` | `str` | Yes | Unique nonce string |
|
|
196
|
+
|
|
197
|
+
**Example Verification (Flask)**
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
from flask import request
|
|
202
|
+
|
|
203
|
+
@app.route('/webhooks/mmpay', methods=['POST'])
|
|
204
|
+
def mmpay_webhook():
|
|
205
|
+
payload_str = request.data.decode('utf-8')
|
|
206
|
+
nonce = request.headers.get('X-Mmpay-Nonce')
|
|
207
|
+
signature = request.headers.get('X-Mmpay-Signature')
|
|
208
|
+
|
|
209
|
+
try:
|
|
210
|
+
is_valid = sdk.verify_cb(payload_str, nonce, signature)
|
|
211
|
+
|
|
212
|
+
if is_valid:
|
|
213
|
+
return "Verified", 200
|
|
214
|
+
else:
|
|
215
|
+
return "Invalid Signature", 400
|
|
216
|
+
|
|
217
|
+
except ValueError as e:
|
|
218
|
+
return str(e), 400
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Error Codes
|
|
222
|
+
|
|
223
|
+
### API Key Layer (SERVER SDK)
|
|
224
|
+
|
|
225
|
+
| Code | Description |
|
|
226
|
+
| :--- | :--- |
|
|
227
|
+
| `KA0001` | Bearer Token Not Included |
|
|
228
|
+
| `KA0002` | API Key Not 'LIVE' |
|
|
229
|
+
| `KA0003` | Signature mismatch |
|
|
230
|
+
| `KA0004` | Internal Server Error |
|
|
231
|
+
| `KA0005` | IP Not whitelisted |
|
|
232
|
+
| `429` | Rate limit hit (1000 req/min) |
|
|
233
|
+
|
|
234
|
+
### JWT Layer (SERVER SDK)
|
|
235
|
+
|
|
236
|
+
| Code | Description |
|
|
237
|
+
| :--- | :--- |
|
|
238
|
+
| `BA001` | `Btoken` nonce token missing |
|
|
239
|
+
| `BA002` | `Btoken` nonce mismatch |
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
MIT
|