mmpay-python-sdk 0.1.0__tar.gz → 0.1.1__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.0 → mmpay_python_sdk-0.1.1}/PKG-INFO +2 -2
- {mmpay_python_sdk-0.1.0 → mmpay_python_sdk-0.1.1}/README.md +63 -14
- {mmpay_python_sdk-0.1.0 → mmpay_python_sdk-0.1.1}/mmpay/client.py +58 -25
- {mmpay_python_sdk-0.1.0 → mmpay_python_sdk-0.1.1}/mmpay_python_sdk.egg-info/PKG-INFO +2 -2
- {mmpay_python_sdk-0.1.0 → mmpay_python_sdk-0.1.1}/setup.py +2 -2
- mmpay_python_sdk-0.1.1/test/test_sdk.py +76 -0
- mmpay_python_sdk-0.1.0/test/test_sdk.py +0 -21
- {mmpay_python_sdk-0.1.0 → mmpay_python_sdk-0.1.1}/mmpay/__init__.py +0 -0
- {mmpay_python_sdk-0.1.0 → mmpay_python_sdk-0.1.1}/mmpay_python_sdk.egg-info/SOURCES.txt +0 -0
- {mmpay_python_sdk-0.1.0 → mmpay_python_sdk-0.1.1}/mmpay_python_sdk.egg-info/dependency_links.txt +0 -0
- {mmpay_python_sdk-0.1.0 → mmpay_python_sdk-0.1.1}/mmpay_python_sdk.egg-info/requires.txt +0 -0
- {mmpay_python_sdk-0.1.0 → mmpay_python_sdk-0.1.1}/mmpay_python_sdk.egg-info/top_level.txt +0 -0
- {mmpay_python_sdk-0.1.0 → mmpay_python_sdk-0.1.1}/setup.cfg +0 -0
|
@@ -64,8 +64,8 @@ Passed to `sdk.pay(params)` or `sdk.sandbox_pay(params)`.
|
|
|
64
64
|
| `orderId` | `str` | Yes | Unique identifier for the order (e.g., "ORD-001"). |
|
|
65
65
|
| `amount` | `number` | Yes | Total transaction amount. |
|
|
66
66
|
| `items` | `List[Item]` | Yes | A list of items included in the order (see table below). |
|
|
67
|
-
| `currency` | `str` | No | Currency code (e.g., "MMK", "USD"). |
|
|
68
67
|
| `callbackUrl` | `str` | No | URL where the webhook callback will be sent. |
|
|
68
|
+
| `customMessage` | `str` | No | URL where the webhook callback will be sent. |
|
|
69
69
|
|
|
70
70
|
### 2. Item Object
|
|
71
71
|
|
|
@@ -83,9 +83,9 @@ try:
|
|
|
83
83
|
payment_request = {
|
|
84
84
|
"orderId": "ORD-SANDBOX-001",
|
|
85
85
|
"amount": 5000, # Amount in minor units (e.g., cents) or as required
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"items": [
|
|
86
|
+
"callbackUrl": "https://your-site.com/webhook/mmpay", # Optional
|
|
87
|
+
"customMessage": "Your Custom Messages", # Optional
|
|
88
|
+
"items": [ # Optional
|
|
89
89
|
{
|
|
90
90
|
"name": "Premium Subscription",
|
|
91
91
|
"amount": 5000,
|
|
@@ -109,9 +109,15 @@ For production environments, use the `pay` method.
|
|
|
109
109
|
try:
|
|
110
110
|
payment_request = {
|
|
111
111
|
"orderId": "ORD-LIVE-98765",
|
|
112
|
-
"amount":
|
|
113
|
-
"
|
|
114
|
-
|
|
112
|
+
"amount": 5000, # Amount in minor units (e.g., cents) or as required
|
|
113
|
+
"callbackUrl": "https://your-site.com/webhook/mmpay", # Optional
|
|
114
|
+
"customMessage": "Your Custom Messages", # Optional
|
|
115
|
+
"items": [ # Optional
|
|
116
|
+
{
|
|
117
|
+
"name": "Premium Subscription",
|
|
118
|
+
"amount": 5000,
|
|
119
|
+
"quantity": 1
|
|
120
|
+
}
|
|
115
121
|
]
|
|
116
122
|
}
|
|
117
123
|
|
|
@@ -125,15 +131,34 @@ except Exception as e:
|
|
|
125
131
|
|
|
126
132
|
### 3. Verify Callback (Webhook)
|
|
127
133
|
|
|
128
|
-
When MMPay sends a callback to your `callbackUrl`, you must verify the request signature to ensure it is genuine.
|
|
134
|
+
When MMPay sends a callback to your `callbackUrl`, you must verify the request signature to ensure it is genuine. If not provide, it will fallback to default cb URL provided in your console
|
|
135
|
+
|
|
136
|
+
**Handling callbacks**
|
|
137
|
+
|
|
138
|
+
Incoming HTTP POST Parameters
|
|
139
|
+
|
|
140
|
+
Header
|
|
129
141
|
|
|
130
|
-
|
|
142
|
+
| Field Name | Type | Required | Description |
|
|
143
|
+
| :--- | :--- | :--- | :--- |
|
|
144
|
+
| **Content-Type** | `string` | Yes | 'application/json' |
|
|
145
|
+
| **X-Mmpay-Signature** | `string` | Yes | '34834890vfgh9hnf94irfg_48932i4rt90349849' |
|
|
146
|
+
| **X-Mmpay-Nonce** | `string` | Yes | '94843943949349' |
|
|
147
|
+
|
|
148
|
+
Body
|
|
149
|
+
|
|
150
|
+
| Field Name | Type | Required | Description |
|
|
151
|
+
| :--- | :--- | :--- | :--- |
|
|
152
|
+
| **orderId** | `string` | Yes | Unique identifier for the specific order. |
|
|
153
|
+
| **amount** | `number` | Yes | The transaction amount. |
|
|
154
|
+
| **currency** | `string` | Yes | The 3-letter currency code (e.g., MMK, USD). |
|
|
155
|
+
| **vendor** | `string` | Yes | Identifier for the vendor initiating the request. |
|
|
156
|
+
| **method** | `'QR', 'PIN', 'PWA', 'CARD'` | Yes | Identifier for the method. |
|
|
157
|
+
| **status** | `'PENDING','SUCCESS','FAILED','REFUNDED'` | Yes | Current status of the transaction. |
|
|
158
|
+
| **transactionRefId** | `string` | Yes | The reference ID generated by the payment provider. |
|
|
159
|
+
| **callbackUrl** | `string` | No | Optional URL to receive webhooks or updates. |
|
|
160
|
+
| **customMessage** | `string` | No | User provided custom message |
|
|
131
161
|
|
|
132
|
-
| Parameter | Type | Description |
|
|
133
|
-
| :--- | :--- | :--- |
|
|
134
|
-
| `payload` | `str` | The **raw** JSON string body of the incoming request. |
|
|
135
|
-
| `nonce` | `str` | The value of the `X-Mmpay-Nonce` header. |
|
|
136
|
-
| `expected_signature` | `str` | The value of the `X-Mmpay-Signature` header. |
|
|
137
162
|
|
|
138
163
|
**Example using Flask:**
|
|
139
164
|
|
|
@@ -144,6 +169,7 @@ from flask import request
|
|
|
144
169
|
def mmpay_webhook():
|
|
145
170
|
# 1. Get the raw payload body as a string (Crucial for signature check)
|
|
146
171
|
payload_str = request.data.decode('utf-8')
|
|
172
|
+
payload = request.data
|
|
147
173
|
|
|
148
174
|
# 2. Get headers
|
|
149
175
|
nonce = request.headers.get('X-Mmpay-Nonce')
|
|
@@ -155,6 +181,7 @@ def mmpay_webhook():
|
|
|
155
181
|
|
|
156
182
|
if is_valid:
|
|
157
183
|
# Process the order (e.g., mark as paid in DB)
|
|
184
|
+
|
|
158
185
|
return "Verified", 200
|
|
159
186
|
else:
|
|
160
187
|
return "Invalid Signature", 400
|
|
@@ -164,6 +191,28 @@ def mmpay_webhook():
|
|
|
164
191
|
```
|
|
165
192
|
|
|
166
193
|
|
|
194
|
+
### 4. Error Codes
|
|
195
|
+
|
|
196
|
+
##### Api Key Layer Authentication [SERVER SDK]
|
|
197
|
+
| Code | Description |
|
|
198
|
+
| :--- | :--- |
|
|
199
|
+
| **`KA0001`** | Bearer Token Not Included In Your Request |
|
|
200
|
+
| **`KA0002`** | API Key Not 'LIVE' |
|
|
201
|
+
| **`KA0003`** | Signature mismatch |
|
|
202
|
+
| **`KA0004`** | Internal Server Error ( Talk to our support immediately fot this ) |
|
|
203
|
+
| **`KA0005`** | IP Not whitelisted |
|
|
204
|
+
| **`429`** | Ratelimit hit only 1000 request / minute allowed |
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
##### JWT Layer Authentication [SERVER SDK]
|
|
208
|
+
| Code | Description |
|
|
209
|
+
| :--- | :--- |
|
|
210
|
+
| **`BA001`** | `Btoken` is nonce one time token is not included |
|
|
211
|
+
| **`BA002`** | `Btoken` one time nonce mismatch |
|
|
212
|
+
| **`BA000`** | Internal Server Error ( Talk to our support immediately fot this ) |
|
|
213
|
+
| **`429`** | Ratelimit hit only 1000 request / minute allowed |
|
|
214
|
+
|
|
215
|
+
|
|
167
216
|
## License
|
|
168
217
|
|
|
169
218
|
MIT
|
|
@@ -3,21 +3,22 @@ import json
|
|
|
3
3
|
import hmac
|
|
4
4
|
import hashlib
|
|
5
5
|
import requests
|
|
6
|
-
from typing import List, Optional, TypedDict, Dict, Any
|
|
6
|
+
from typing import List, Optional, TypedDict, Dict, Any, Union
|
|
7
7
|
|
|
8
|
-
# --- Type Definitions
|
|
8
|
+
# --- Type Definitions ---
|
|
9
9
|
|
|
10
10
|
class Item(TypedDict):
|
|
11
11
|
name: str
|
|
12
12
|
amount: float
|
|
13
13
|
quantity: int
|
|
14
14
|
|
|
15
|
-
class PaymentRequest(TypedDict):
|
|
15
|
+
class PaymentRequest(TypedDict, total=False):
|
|
16
16
|
orderId: str
|
|
17
17
|
amount: float
|
|
18
|
-
items: List[Item]
|
|
18
|
+
items: Optional[List[Item]]
|
|
19
19
|
currency: Optional[str]
|
|
20
20
|
callbackUrl: Optional[str]
|
|
21
|
+
customMessage: Optional[str] # Added to match TS
|
|
21
22
|
|
|
22
23
|
class XPaymentRequest(PaymentRequest, total=False):
|
|
23
24
|
appId: str
|
|
@@ -27,6 +28,21 @@ class HandShakeRequest(TypedDict):
|
|
|
27
28
|
orderId: str
|
|
28
29
|
nonce: str
|
|
29
30
|
|
|
31
|
+
class HandShakeResponse(TypedDict):
|
|
32
|
+
token: str
|
|
33
|
+
|
|
34
|
+
class CallbackIncomingData(TypedDict):
|
|
35
|
+
orderId: str
|
|
36
|
+
amount: float
|
|
37
|
+
method: str
|
|
38
|
+
currency: str
|
|
39
|
+
vendor: str
|
|
40
|
+
status: str
|
|
41
|
+
condition: str
|
|
42
|
+
transactionRefId: str
|
|
43
|
+
callbackUrl: Optional[str]
|
|
44
|
+
customMessage: Optional[str]
|
|
45
|
+
|
|
30
46
|
class SDKOptions(TypedDict):
|
|
31
47
|
appId: str
|
|
32
48
|
publishableKey: str
|
|
@@ -43,12 +59,14 @@ class MMPaySDK:
|
|
|
43
59
|
self._app_id = options['appId']
|
|
44
60
|
self._publishable_key = options['publishableKey']
|
|
45
61
|
self._secret_key = options['secretKey']
|
|
62
|
+
# Remove trailing slash if present to prevent double slashes in endpoints
|
|
46
63
|
self._api_base_url = options['apiBaseUrl'].rstrip('/')
|
|
47
64
|
self._btoken: Optional[str] = None
|
|
48
65
|
|
|
49
66
|
def _generate_signature(self, body_string: str, nonce: str) -> str:
|
|
50
67
|
"""
|
|
51
68
|
Generates an HMAC SHA256 signature for request integrity.
|
|
69
|
+
Matches: CryptoJS.HmacSHA256(nonce + "." + bodyString, secret)
|
|
52
70
|
"""
|
|
53
71
|
string_to_sign = f"{nonce}.{body_string}"
|
|
54
72
|
return hmac.new(
|
|
@@ -70,11 +88,10 @@ class MMPaySDK:
|
|
|
70
88
|
|
|
71
89
|
# --- Sandbox Methods ---
|
|
72
90
|
|
|
73
|
-
def sandbox_handshake(self, payload: HandShakeRequest) -> Dict[str, Any]:
|
|
91
|
+
def sandbox_handshake(self, payload: HandShakeRequest) -> Union[HandShakeResponse, Dict[str, Any]]:
|
|
74
92
|
endpoint = f"{self._api_base_url}/payments/sandbox-handshake"
|
|
75
93
|
nonce = self._get_nonce()
|
|
76
94
|
|
|
77
|
-
# Ensure payload is serialized exactly as the signature expects
|
|
78
95
|
body_string = self._json_stringify(payload)
|
|
79
96
|
signature = self._generate_signature(body_string, nonce)
|
|
80
97
|
|
|
@@ -93,31 +110,39 @@ class MMPaySDK:
|
|
|
93
110
|
self._btoken = data['token']
|
|
94
111
|
return data
|
|
95
112
|
except requests.exceptions.RequestException as e:
|
|
96
|
-
|
|
97
|
-
return {"error": str(e), "details": response.text if response else None}
|
|
113
|
+
return {"error": str(e), "details": getattr(e.response, 'text', '')}
|
|
98
114
|
|
|
99
115
|
def sandbox_pay(self, params: PaymentRequest) -> Dict[str, Any]:
|
|
100
116
|
endpoint = f"{self._api_base_url}/payments/sandbox-create"
|
|
101
117
|
nonce = self._get_nonce()
|
|
102
118
|
|
|
103
119
|
# Construct payload
|
|
104
|
-
|
|
120
|
+
# Note: We manually build the dict to ensure we don't include None/null
|
|
121
|
+
# for optional fields, which would break the signature vs JS stringify.
|
|
122
|
+
xpayload: Dict[str, Any] = {
|
|
105
123
|
"appId": self._app_id,
|
|
106
124
|
"nonce": nonce,
|
|
107
125
|
"amount": params['amount'],
|
|
108
126
|
"orderId": params['orderId'],
|
|
109
|
-
"items": params['items'],
|
|
110
127
|
}
|
|
111
|
-
|
|
128
|
+
|
|
129
|
+
if params.get('items'):
|
|
130
|
+
xpayload['items'] = params['items']
|
|
131
|
+
if params.get('callbackUrl'):
|
|
112
132
|
xpayload['callbackUrl'] = params['callbackUrl']
|
|
113
|
-
if '
|
|
114
|
-
xpayload['
|
|
133
|
+
if params.get('customMessage'):
|
|
134
|
+
xpayload['customMessage'] = params['customMessage']
|
|
115
135
|
|
|
116
136
|
body_string = self._json_stringify(xpayload)
|
|
117
137
|
signature = self._generate_signature(body_string, nonce)
|
|
118
138
|
|
|
119
|
-
# Perform handshake first (as per TS
|
|
120
|
-
|
|
139
|
+
# Perform handshake first (using the nonce from the payload logic as per TS)
|
|
140
|
+
handshake_payload: HandShakeRequest = {
|
|
141
|
+
'orderId': str(xpayload['orderId']),
|
|
142
|
+
'nonce': str(xpayload['nonce'])
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
handshake_res = self.sandbox_handshake(handshake_payload)
|
|
121
146
|
if 'error' in handshake_res:
|
|
122
147
|
return handshake_res
|
|
123
148
|
|
|
@@ -134,11 +159,11 @@ class MMPaySDK:
|
|
|
134
159
|
response.raise_for_status()
|
|
135
160
|
return response.json()
|
|
136
161
|
except requests.exceptions.RequestException as e:
|
|
137
|
-
return {"error": str(e), "details":
|
|
162
|
+
return {"error": str(e), "details": getattr(e.response, 'text', '')}
|
|
138
163
|
|
|
139
164
|
# --- Production Methods ---
|
|
140
165
|
|
|
141
|
-
def handshake(self, payload: HandShakeRequest) -> Dict[str, Any]:
|
|
166
|
+
def handshake(self, payload: HandShakeRequest) -> Union[HandShakeResponse, Dict[str, Any]]:
|
|
142
167
|
endpoint = f"{self._api_base_url}/payments/handshake"
|
|
143
168
|
nonce = self._get_nonce()
|
|
144
169
|
|
|
@@ -160,29 +185,36 @@ class MMPaySDK:
|
|
|
160
185
|
self._btoken = data['token']
|
|
161
186
|
return data
|
|
162
187
|
except requests.exceptions.RequestException as e:
|
|
163
|
-
return {"error": str(e), "details":
|
|
188
|
+
return {"error": str(e), "details": getattr(e.response, 'text', '')}
|
|
164
189
|
|
|
165
190
|
def pay(self, params: PaymentRequest) -> Dict[str, Any]:
|
|
166
191
|
endpoint = f"{self._api_base_url}/payments/create"
|
|
167
192
|
nonce = self._get_nonce()
|
|
168
193
|
|
|
169
|
-
xpayload:
|
|
194
|
+
xpayload: Dict[str, Any] = {
|
|
170
195
|
"appId": self._app_id,
|
|
171
196
|
"nonce": nonce,
|
|
172
197
|
"amount": params['amount'],
|
|
173
198
|
"orderId": params['orderId'],
|
|
174
|
-
"items": params['items'],
|
|
175
199
|
}
|
|
176
|
-
|
|
200
|
+
|
|
201
|
+
if params.get('items'):
|
|
202
|
+
xpayload['items'] = params['items']
|
|
203
|
+
if params.get('callbackUrl'):
|
|
177
204
|
xpayload['callbackUrl'] = params['callbackUrl']
|
|
178
|
-
if '
|
|
179
|
-
xpayload['
|
|
205
|
+
if params.get('customMessage'):
|
|
206
|
+
xpayload['customMessage'] = params['customMessage']
|
|
180
207
|
|
|
181
208
|
body_string = self._json_stringify(xpayload)
|
|
182
209
|
signature = self._generate_signature(body_string, nonce)
|
|
183
210
|
|
|
184
211
|
# Perform handshake
|
|
185
|
-
|
|
212
|
+
handshake_payload: HandShakeRequest = {
|
|
213
|
+
'orderId': str(xpayload['orderId']),
|
|
214
|
+
'nonce': str(xpayload['nonce'])
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
handshake_res = self.handshake(handshake_payload)
|
|
186
218
|
if 'error' in handshake_res:
|
|
187
219
|
return handshake_res
|
|
188
220
|
|
|
@@ -199,7 +231,7 @@ class MMPaySDK:
|
|
|
199
231
|
response.raise_for_status()
|
|
200
232
|
return response.json()
|
|
201
233
|
except requests.exceptions.RequestException as e:
|
|
202
|
-
return {"error": str(e), "details":
|
|
234
|
+
return {"error": str(e), "details": getattr(e.response, 'text', '')}
|
|
203
235
|
|
|
204
236
|
# --- Verification ---
|
|
205
237
|
|
|
@@ -218,6 +250,7 @@ class MMPaySDK:
|
|
|
218
250
|
).hexdigest()
|
|
219
251
|
|
|
220
252
|
if generated_signature != expected_signature:
|
|
253
|
+
# Using print for logging as per TS console.error
|
|
221
254
|
print(f"Signature mismatch: gen={generated_signature}, exp={expected_signature}")
|
|
222
255
|
return False
|
|
223
256
|
|
|
@@ -2,9 +2,9 @@ from setuptools import setup, find_packages
|
|
|
2
2
|
|
|
3
3
|
setup(
|
|
4
4
|
name="mmpay-python-sdk",
|
|
5
|
-
version="0.1.
|
|
5
|
+
version="0.1.1",
|
|
6
6
|
description="Python SDK for MMPay (Ported from JS)",
|
|
7
|
-
author="
|
|
7
|
+
author="MyanMyanPay",
|
|
8
8
|
packages=find_packages(),
|
|
9
9
|
install_requires=[
|
|
10
10
|
"requests",
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import os
|
|
3
|
+
import random
|
|
4
|
+
import string
|
|
5
|
+
from dotenv import load_dotenv
|
|
6
|
+
|
|
7
|
+
from mmpay import MMPaySDK
|
|
8
|
+
# from mmpay_sdk import MMPaySDK # Assumes the SDK is saved in mmpay_sdk.py
|
|
9
|
+
|
|
10
|
+
# Load environment variables from .env file
|
|
11
|
+
load_dotenv()
|
|
12
|
+
|
|
13
|
+
def generate_secure_random_string(length: int) -> str:
|
|
14
|
+
"""
|
|
15
|
+
Generates a random alphanumeric string.
|
|
16
|
+
"""
|
|
17
|
+
# Using random.choices to generate a string of requested length
|
|
18
|
+
# This mimics the base36 behavior of the JS example
|
|
19
|
+
chars = string.ascii_lowercase + string.digits
|
|
20
|
+
return ''.join(random.choices(chars, k=length))
|
|
21
|
+
|
|
22
|
+
def start():
|
|
23
|
+
"""
|
|
24
|
+
Executes the payment call and measures network latency.
|
|
25
|
+
"""
|
|
26
|
+
# Initialize SDK
|
|
27
|
+
# specific env keys matching your JS example
|
|
28
|
+
mmpay = MMPaySDK({
|
|
29
|
+
'appId': os.getenv('APP_ID', ''),
|
|
30
|
+
'publishableKey': os.getenv('PUB_KEY', ''),
|
|
31
|
+
'secretKey': os.getenv('SEC_KEY', ''),
|
|
32
|
+
'apiBaseUrl': os.getenv('BASEURL', '')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
# Generate Order ID
|
|
36
|
+
order_id = generate_secure_random_string(6)
|
|
37
|
+
|
|
38
|
+
# Start Timer
|
|
39
|
+
# time.perf_counter() is the Python equivalent to performance.now()
|
|
40
|
+
start_time = time.perf_counter()
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
payload = {
|
|
44
|
+
"orderId": order_id,
|
|
45
|
+
"amount": 1500,
|
|
46
|
+
"customMessage": "MyanMyanPay Is The Best",
|
|
47
|
+
"items": [{"name": "Items", "amount": 3000, "quantity": 1}]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Execute Payment (Synchronous in Python version)
|
|
51
|
+
response = mmpay.sandbox_pay(payload)
|
|
52
|
+
|
|
53
|
+
# End Timer
|
|
54
|
+
end_time = time.perf_counter()
|
|
55
|
+
|
|
56
|
+
# Calculate latency in milliseconds
|
|
57
|
+
latency_ms = (end_time - start_time) * 1000
|
|
58
|
+
|
|
59
|
+
print(f"\n--- Transaction Request Successful ---")
|
|
60
|
+
print(f"Order ID: {order_id}")
|
|
61
|
+
print(f"**Network Latency: {latency_ms:.3f} ms**")
|
|
62
|
+
print(f"Response: {response}")
|
|
63
|
+
print(f"------------------------------\n")
|
|
64
|
+
|
|
65
|
+
except Exception as error:
|
|
66
|
+
end_time = time.perf_counter()
|
|
67
|
+
latency_ms = (end_time - start_time) * 1000
|
|
68
|
+
|
|
69
|
+
print(f"\n--- Transaction Request Failed ---")
|
|
70
|
+
print(f"Order ID: {order_id}")
|
|
71
|
+
print(f"**Network Latency: {latency_ms:.3f} ms**")
|
|
72
|
+
print(f"Error Message: {str(error)}")
|
|
73
|
+
print(f"--------------------------\n")
|
|
74
|
+
|
|
75
|
+
if __name__ == "__main__":
|
|
76
|
+
start()
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
from mmpay import MMPaySDK
|
|
2
|
-
|
|
3
|
-
# Initialize
|
|
4
|
-
sdk = MMPaySDK({
|
|
5
|
-
"appId": "your_app_id",
|
|
6
|
-
"publishableKey": "your_pub_key",
|
|
7
|
-
"secretKey": "your_secret_key",
|
|
8
|
-
"apiBaseUrl": "https://api.mmpay.com" # Example URL
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
# Create a Payment (Sandbox)
|
|
12
|
-
response = sdk.sandbox_pay({
|
|
13
|
-
"orderId": "ORD-123456789",
|
|
14
|
-
"amount": 1000,
|
|
15
|
-
"callbackUrl": "https://yoursite.com/callback",
|
|
16
|
-
"items": [
|
|
17
|
-
{"name": "Test Item", "amount": 1000, "quantity": 1}
|
|
18
|
-
]
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
print(response)
|
|
File without changes
|
|
File without changes
|
{mmpay_python_sdk-0.1.0 → mmpay_python_sdk-0.1.1}/mmpay_python_sdk.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|