mmpay-python-sdk 0.1.0__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/PKG-INFO +11 -0
- mmpay_python_sdk-0.1.0/README.md +169 -0
- mmpay_python_sdk-0.1.0/mmpay/__init__.py +3 -0
- mmpay_python_sdk-0.1.0/mmpay/client.py +224 -0
- mmpay_python_sdk-0.1.0/mmpay_python_sdk.egg-info/PKG-INFO +11 -0
- mmpay_python_sdk-0.1.0/mmpay_python_sdk.egg-info/SOURCES.txt +10 -0
- mmpay_python_sdk-0.1.0/mmpay_python_sdk.egg-info/dependency_links.txt +1 -0
- mmpay_python_sdk-0.1.0/mmpay_python_sdk.egg-info/requires.txt +1 -0
- mmpay_python_sdk-0.1.0/mmpay_python_sdk.egg-info/top_level.txt +1 -0
- mmpay_python_sdk-0.1.0/setup.cfg +4 -0
- mmpay_python_sdk-0.1.0/setup.py +13 -0
- mmpay_python_sdk-0.1.0/test/test_sdk.py +21 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mmpay-python-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for MMPay (Ported from JS)
|
|
5
|
+
Author: Your Name
|
|
6
|
+
Requires-Python: >=3.6
|
|
7
|
+
Requires-Dist: requests
|
|
8
|
+
Dynamic: author
|
|
9
|
+
Dynamic: requires-dist
|
|
10
|
+
Dynamic: requires-python
|
|
11
|
+
Dynamic: summary
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
|
|
2
|
+
# MMPay Python SDK
|
|
3
|
+
|
|
4
|
+
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, handshake authentication, and callback verification.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- **Sandbox & Production Support**: dedicated methods for both environments.
|
|
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
|
+
Install the package via pip:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install mmpay-python-sdk
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Configuration
|
|
22
|
+
|
|
23
|
+
To use the SDK, you need your **App ID**, **Publishable Key**, and **Secret Key** provided by the MMPay dashboard.
|
|
24
|
+
|
|
25
|
+
Used when instantiating `MMPaySDK(options)`.
|
|
26
|
+
|
|
27
|
+
| Parameter | Type | Required | Description |
|
|
28
|
+
| :--- | :--- | :--- | :--- |
|
|
29
|
+
| `appId` | `str` | Yes | Your unique Application ID. |
|
|
30
|
+
| `publishableKey` | `str` | Yes | Public key for authentication. |
|
|
31
|
+
| `secretKey` | `str` | Yes | Private key used for signing requests (HMAC). |
|
|
32
|
+
| `apiBaseUrl` | `str` | Yes | The base URL for the MMPay API. |
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from mmpay import MMPaySDK
|
|
36
|
+
|
|
37
|
+
# Initialize the SDK
|
|
38
|
+
options = {
|
|
39
|
+
"appId": "YOUR_APP_ID",
|
|
40
|
+
"publishableKey": "YOUR_PUBLISHABLE_KEY",
|
|
41
|
+
"secretKey": "YOUR_SECRET_KEY",
|
|
42
|
+
"apiBaseUrl": "[https://xxx.myanmyanpay.com](https://xxx.myanmyanpay.com)" # Replace with actual API Base URL [ Register With Us]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
sdk = MMPaySDK(options)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
### 1. Create a Payment (Sandbox)
|
|
54
|
+
|
|
55
|
+
Use `sandbox_pay` to create a payment order in the Sandbox environment. This handles the handshake and signature generation automatically.
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
### 1. Payment Request (`pay` / `sandbox_pay`)
|
|
59
|
+
|
|
60
|
+
Passed to `sdk.pay(params)` or `sdk.sandbox_pay(params)`.
|
|
61
|
+
|
|
62
|
+
| Parameter | Type | Required | Description |
|
|
63
|
+
| :--- | :--- | :--- | :--- |
|
|
64
|
+
| `orderId` | `str` | Yes | Unique identifier for the order (e.g., "ORD-001"). |
|
|
65
|
+
| `amount` | `number` | Yes | Total transaction amount. |
|
|
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
|
+
| `callbackUrl` | `str` | No | URL where the webhook callback will be sent. |
|
|
69
|
+
|
|
70
|
+
### 2. Item Object
|
|
71
|
+
|
|
72
|
+
Used inside the `items` list of a Payment Request.
|
|
73
|
+
|
|
74
|
+
| Parameter | Type | Required | Description |
|
|
75
|
+
| :--- | :--- | :--- | :--- |
|
|
76
|
+
| `name` | `str` | Yes | Name of the product or service. |
|
|
77
|
+
| `amount` | `number` | Yes | Price per unit. |
|
|
78
|
+
| `quantity` | `int` | Yes | Quantity of the item. |
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
try:
|
|
83
|
+
payment_request = {
|
|
84
|
+
"orderId": "ORD-SANDBOX-001",
|
|
85
|
+
"amount": 5000, # Amount in minor units (e.g., cents) or as required
|
|
86
|
+
"currency": "MMK",
|
|
87
|
+
"callbackUrl": "[https://your-site.com/webhook/mmpay](https://your-site.com/webhook/mmpay)",
|
|
88
|
+
"items": [
|
|
89
|
+
{
|
|
90
|
+
"name": "Premium Subscription",
|
|
91
|
+
"amount": 5000,
|
|
92
|
+
"quantity": 1
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
response = sdk.sandbox_pay(payment_request)
|
|
98
|
+
print("Payment Response:", response)
|
|
99
|
+
|
|
100
|
+
except Exception as e:
|
|
101
|
+
print("Error creating payment:", e)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 2. Create a Payment (Production)
|
|
105
|
+
|
|
106
|
+
For production environments, use the `pay` method.
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
try:
|
|
110
|
+
payment_request = {
|
|
111
|
+
"orderId": "ORD-LIVE-98765",
|
|
112
|
+
"amount": 10000,
|
|
113
|
+
"items": [
|
|
114
|
+
{"name": "E-Commerce Item", "amount": 10000, "quantity": 1}
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
# Helper automatically handles the handshake and signing
|
|
119
|
+
response = sdk.pay(payment_request)
|
|
120
|
+
print("Production Payment URL:", response.get('url'))
|
|
121
|
+
|
|
122
|
+
except Exception as e:
|
|
123
|
+
print("Error:", e)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 3. Verify Callback (Webhook)
|
|
127
|
+
|
|
128
|
+
When MMPay sends a callback to your `callbackUrl`, you must verify the request signature to ensure it is genuine.
|
|
129
|
+
|
|
130
|
+
### Callback Verification (`verify_cb`)
|
|
131
|
+
|
|
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
|
+
|
|
138
|
+
**Example using Flask:**
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from flask import request
|
|
142
|
+
|
|
143
|
+
@app.route('/webhook/mmpay', methods=['POST'])
|
|
144
|
+
def mmpay_webhook():
|
|
145
|
+
# 1. Get the raw payload body as a string (Crucial for signature check)
|
|
146
|
+
payload_str = request.data.decode('utf-8')
|
|
147
|
+
|
|
148
|
+
# 2. Get headers
|
|
149
|
+
nonce = request.headers.get('X-Mmpay-Nonce')
|
|
150
|
+
signature = request.headers.get('X-Mmpay-Signature')
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
# 3. Verify
|
|
154
|
+
is_valid = sdk.verify_cb(payload_str, nonce, signature)
|
|
155
|
+
|
|
156
|
+
if is_valid:
|
|
157
|
+
# Process the order (e.g., mark as paid in DB)
|
|
158
|
+
return "Verified", 200
|
|
159
|
+
else:
|
|
160
|
+
return "Invalid Signature", 400
|
|
161
|
+
|
|
162
|
+
except ValueError as e:
|
|
163
|
+
return str(e), 400
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import json
|
|
3
|
+
import hmac
|
|
4
|
+
import hashlib
|
|
5
|
+
import requests
|
|
6
|
+
from typing import List, Optional, TypedDict, Dict, Any
|
|
7
|
+
|
|
8
|
+
# --- Type Definitions to mirror your Interfaces ---
|
|
9
|
+
|
|
10
|
+
class Item(TypedDict):
|
|
11
|
+
name: str
|
|
12
|
+
amount: float
|
|
13
|
+
quantity: int
|
|
14
|
+
|
|
15
|
+
class PaymentRequest(TypedDict):
|
|
16
|
+
orderId: str
|
|
17
|
+
amount: float
|
|
18
|
+
items: List[Item]
|
|
19
|
+
currency: Optional[str]
|
|
20
|
+
callbackUrl: Optional[str]
|
|
21
|
+
|
|
22
|
+
class XPaymentRequest(PaymentRequest, total=False):
|
|
23
|
+
appId: str
|
|
24
|
+
nonce: str
|
|
25
|
+
|
|
26
|
+
class HandShakeRequest(TypedDict):
|
|
27
|
+
orderId: str
|
|
28
|
+
nonce: str
|
|
29
|
+
|
|
30
|
+
class SDKOptions(TypedDict):
|
|
31
|
+
appId: str
|
|
32
|
+
publishableKey: str
|
|
33
|
+
secretKey: str
|
|
34
|
+
apiBaseUrl: str
|
|
35
|
+
|
|
36
|
+
# --- Main SDK Class ---
|
|
37
|
+
|
|
38
|
+
class MMPaySDK:
|
|
39
|
+
def __init__(self, options: SDKOptions):
|
|
40
|
+
"""
|
|
41
|
+
Initializes the SDK with the merchant's keys and the API endpoint.
|
|
42
|
+
"""
|
|
43
|
+
self._app_id = options['appId']
|
|
44
|
+
self._publishable_key = options['publishableKey']
|
|
45
|
+
self._secret_key = options['secretKey']
|
|
46
|
+
self._api_base_url = options['apiBaseUrl'].rstrip('/')
|
|
47
|
+
self._btoken: Optional[str] = None
|
|
48
|
+
|
|
49
|
+
def _generate_signature(self, body_string: str, nonce: str) -> str:
|
|
50
|
+
"""
|
|
51
|
+
Generates an HMAC SHA256 signature for request integrity.
|
|
52
|
+
"""
|
|
53
|
+
string_to_sign = f"{nonce}.{body_string}"
|
|
54
|
+
return hmac.new(
|
|
55
|
+
self._secret_key.encode('utf-8'),
|
|
56
|
+
string_to_sign.encode('utf-8'),
|
|
57
|
+
hashlib.sha256
|
|
58
|
+
).hexdigest()
|
|
59
|
+
|
|
60
|
+
def _get_nonce(self) -> str:
|
|
61
|
+
"""Helper to get current timestamp as string (milliseconds)"""
|
|
62
|
+
return str(int(time.time() * 1000))
|
|
63
|
+
|
|
64
|
+
def _json_stringify(self, data: Any) -> str:
|
|
65
|
+
"""
|
|
66
|
+
Mimics JS JSON.stringify exactly (no spaces).
|
|
67
|
+
Crucial for signature verification.
|
|
68
|
+
"""
|
|
69
|
+
return json.dumps(data, separators=(',', ':'))
|
|
70
|
+
|
|
71
|
+
# --- Sandbox Methods ---
|
|
72
|
+
|
|
73
|
+
def sandbox_handshake(self, payload: HandShakeRequest) -> Dict[str, Any]:
|
|
74
|
+
endpoint = f"{self._api_base_url}/payments/sandbox-handshake"
|
|
75
|
+
nonce = self._get_nonce()
|
|
76
|
+
|
|
77
|
+
# Ensure payload is serialized exactly as the signature expects
|
|
78
|
+
body_string = self._json_stringify(payload)
|
|
79
|
+
signature = self._generate_signature(body_string, nonce)
|
|
80
|
+
|
|
81
|
+
headers = {
|
|
82
|
+
'Authorization': f"Bearer {self._publishable_key}",
|
|
83
|
+
'X-Mmpay-Nonce': nonce,
|
|
84
|
+
'X-Mmpay-Signature': signature,
|
|
85
|
+
'Content-Type': 'application/json',
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
response = requests.post(endpoint, data=body_string, headers=headers)
|
|
90
|
+
response.raise_for_status()
|
|
91
|
+
data = response.json()
|
|
92
|
+
if 'token' in data:
|
|
93
|
+
self._btoken = data['token']
|
|
94
|
+
return data
|
|
95
|
+
except requests.exceptions.RequestException as e:
|
|
96
|
+
# In a real SDK, you might want to raise custom exceptions here
|
|
97
|
+
return {"error": str(e), "details": response.text if response else None}
|
|
98
|
+
|
|
99
|
+
def sandbox_pay(self, params: PaymentRequest) -> Dict[str, Any]:
|
|
100
|
+
endpoint = f"{self._api_base_url}/payments/sandbox-create"
|
|
101
|
+
nonce = self._get_nonce()
|
|
102
|
+
|
|
103
|
+
# Construct payload
|
|
104
|
+
xpayload: XPaymentRequest = {
|
|
105
|
+
"appId": self._app_id,
|
|
106
|
+
"nonce": nonce,
|
|
107
|
+
"amount": params['amount'],
|
|
108
|
+
"orderId": params['orderId'],
|
|
109
|
+
"items": params['items'],
|
|
110
|
+
}
|
|
111
|
+
if 'callbackUrl' in params:
|
|
112
|
+
xpayload['callbackUrl'] = params['callbackUrl']
|
|
113
|
+
if 'currency' in params:
|
|
114
|
+
xpayload['currency'] = params['currency']
|
|
115
|
+
|
|
116
|
+
body_string = self._json_stringify(xpayload)
|
|
117
|
+
signature = self._generate_signature(body_string, nonce)
|
|
118
|
+
|
|
119
|
+
# Perform handshake first (as per TS logic)
|
|
120
|
+
handshake_res = self.sandbox_handshake({'orderId': xpayload['orderId'], 'nonce': xpayload['nonce']})
|
|
121
|
+
if 'error' in handshake_res:
|
|
122
|
+
return handshake_res
|
|
123
|
+
|
|
124
|
+
headers = {
|
|
125
|
+
'Authorization': f"Bearer {self._publishable_key}",
|
|
126
|
+
'X-Mmpay-Btoken': self._btoken,
|
|
127
|
+
'X-Mmpay-Nonce': nonce,
|
|
128
|
+
'X-Mmpay-Signature': signature,
|
|
129
|
+
'Content-Type': 'application/json',
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
response = requests.post(endpoint, data=body_string, headers=headers)
|
|
134
|
+
response.raise_for_status()
|
|
135
|
+
return response.json()
|
|
136
|
+
except requests.exceptions.RequestException as e:
|
|
137
|
+
return {"error": str(e), "details": response.text if response else None}
|
|
138
|
+
|
|
139
|
+
# --- Production Methods ---
|
|
140
|
+
|
|
141
|
+
def handshake(self, payload: HandShakeRequest) -> Dict[str, Any]:
|
|
142
|
+
endpoint = f"{self._api_base_url}/payments/handshake"
|
|
143
|
+
nonce = self._get_nonce()
|
|
144
|
+
|
|
145
|
+
body_string = self._json_stringify(payload)
|
|
146
|
+
signature = self._generate_signature(body_string, nonce)
|
|
147
|
+
|
|
148
|
+
headers = {
|
|
149
|
+
'Authorization': f"Bearer {self._publishable_key}",
|
|
150
|
+
'X-Mmpay-Nonce': nonce,
|
|
151
|
+
'X-Mmpay-Signature': signature,
|
|
152
|
+
'Content-Type': 'application/json',
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
try:
|
|
156
|
+
response = requests.post(endpoint, data=body_string, headers=headers)
|
|
157
|
+
response.raise_for_status()
|
|
158
|
+
data = response.json()
|
|
159
|
+
if 'token' in data:
|
|
160
|
+
self._btoken = data['token']
|
|
161
|
+
return data
|
|
162
|
+
except requests.exceptions.RequestException as e:
|
|
163
|
+
return {"error": str(e), "details": response.text if response else None}
|
|
164
|
+
|
|
165
|
+
def pay(self, params: PaymentRequest) -> Dict[str, Any]:
|
|
166
|
+
endpoint = f"{self._api_base_url}/payments/create"
|
|
167
|
+
nonce = self._get_nonce()
|
|
168
|
+
|
|
169
|
+
xpayload: XPaymentRequest = {
|
|
170
|
+
"appId": self._app_id,
|
|
171
|
+
"nonce": nonce,
|
|
172
|
+
"amount": params['amount'],
|
|
173
|
+
"orderId": params['orderId'],
|
|
174
|
+
"items": params['items'],
|
|
175
|
+
}
|
|
176
|
+
if 'callbackUrl' in params:
|
|
177
|
+
xpayload['callbackUrl'] = params['callbackUrl']
|
|
178
|
+
if 'currency' in params:
|
|
179
|
+
xpayload['currency'] = params['currency']
|
|
180
|
+
|
|
181
|
+
body_string = self._json_stringify(xpayload)
|
|
182
|
+
signature = self._generate_signature(body_string, nonce)
|
|
183
|
+
|
|
184
|
+
# Perform handshake
|
|
185
|
+
handshake_res = self.handshake({'orderId': xpayload['orderId'], 'nonce': xpayload['nonce']})
|
|
186
|
+
if 'error' in handshake_res:
|
|
187
|
+
return handshake_res
|
|
188
|
+
|
|
189
|
+
headers = {
|
|
190
|
+
'Authorization': f"Bearer {self._publishable_key}",
|
|
191
|
+
'X-Mmpay-Btoken': self._btoken,
|
|
192
|
+
'X-Mmpay-Nonce': nonce,
|
|
193
|
+
'X-Mmpay-Signature': signature,
|
|
194
|
+
'Content-Type': 'application/json',
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
response = requests.post(endpoint, data=body_string, headers=headers)
|
|
199
|
+
response.raise_for_status()
|
|
200
|
+
return response.json()
|
|
201
|
+
except requests.exceptions.RequestException as e:
|
|
202
|
+
return {"error": str(e), "details": response.text if response else None}
|
|
203
|
+
|
|
204
|
+
# --- Verification ---
|
|
205
|
+
|
|
206
|
+
def verify_cb(self, payload: str, nonce: str, expected_signature: str) -> bool:
|
|
207
|
+
"""
|
|
208
|
+
Verifies the signature of a callback request.
|
|
209
|
+
"""
|
|
210
|
+
if not payload or not nonce or not expected_signature:
|
|
211
|
+
raise ValueError("Callback verification failed: Missing payload, nonce, or signature.")
|
|
212
|
+
|
|
213
|
+
string_to_sign = f"{nonce}.{payload}"
|
|
214
|
+
generated_signature = hmac.new(
|
|
215
|
+
self._secret_key.encode('utf-8'),
|
|
216
|
+
string_to_sign.encode('utf-8'),
|
|
217
|
+
hashlib.sha256
|
|
218
|
+
).hexdigest()
|
|
219
|
+
|
|
220
|
+
if generated_signature != expected_signature:
|
|
221
|
+
print(f"Signature mismatch: gen={generated_signature}, exp={expected_signature}")
|
|
222
|
+
return False
|
|
223
|
+
|
|
224
|
+
return True
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mmpay-python-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for MMPay (Ported from JS)
|
|
5
|
+
Author: Your Name
|
|
6
|
+
Requires-Python: >=3.6
|
|
7
|
+
Requires-Dist: requests
|
|
8
|
+
Dynamic: author
|
|
9
|
+
Dynamic: requires-dist
|
|
10
|
+
Dynamic: requires-python
|
|
11
|
+
Dynamic: summary
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
mmpay/__init__.py
|
|
4
|
+
mmpay/client.py
|
|
5
|
+
mmpay_python_sdk.egg-info/PKG-INFO
|
|
6
|
+
mmpay_python_sdk.egg-info/SOURCES.txt
|
|
7
|
+
mmpay_python_sdk.egg-info/dependency_links.txt
|
|
8
|
+
mmpay_python_sdk.egg-info/requires.txt
|
|
9
|
+
mmpay_python_sdk.egg-info/top_level.txt
|
|
10
|
+
test/test_sdk.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mmpay
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="mmpay-python-sdk",
|
|
5
|
+
version="0.1.0",
|
|
6
|
+
description="Python SDK for MMPay (Ported from JS)",
|
|
7
|
+
author="Your Name",
|
|
8
|
+
packages=find_packages(),
|
|
9
|
+
install_requires=[
|
|
10
|
+
"requests",
|
|
11
|
+
],
|
|
12
|
+
python_requires=">=3.6",
|
|
13
|
+
)
|
|
@@ -0,0 +1,21 @@
|
|
|
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)
|