Skip to content

Commit d2e4209

Browse files
committed
Add MONEI Connect support with account ID and custom user agent
- Enhance MoneiClient to support setting account ID for partners - Add validation for user agent when using account ID - Implement methods to set and remove account ID dynamically - Update README with MONEI Connect integration examples - Add test cases for account ID and user agent functionality
1 parent 18e416c commit d2e4209

File tree

5 files changed

+510
-81
lines changed

5 files changed

+510
-81
lines changed

Monei/__init__.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# flake8: noqa
22

33
"""
4-
MONEI API v1
4+
MONEI API v1
55
6-
<p>The MONEI API is organized around <a href=\"https://en.wikipedia.org/wiki/Representational_State_Transfer\">REST</a> principles. Our API is designed to be intuitive and developer-friendly.</p> <h3>Base URL</h3> <p>All API requests should be made to:</p> <pre><code>https://api.monei.com/v1 </code></pre> <h3>Environment</h3> <p>MONEI provides two environments:</p> <ul> <li><strong>Test Environment</strong>: For development and testing without processing real payments</li> <li><strong>Live Environment</strong>: For processing real transactions in production</li> </ul> <h3>Client Libraries</h3> <p>We provide official SDKs to simplify integration:</p> <ul> <li><a href=\"https://github.com/MONEI/monei-php-sdk\">PHP SDK</a></li> <li><a href=\"https://github.com/MONEI/monei-python-sdk\">Python SDK</a></li> <li><a href=\"https://github.com/MONEI/monei-node-sdk\">Node.js SDK</a></li> <li><a href=\"https://postman.monei.com/\">Postman Collection</a></li> </ul> <p>Our SDKs handle authentication, error handling, and request formatting automatically.</p> <h3>Important Requirements</h3> <ul> <li>All API requests must be made over HTTPS</li> <li>If you are not using our official SDKs, you <strong>must provide a valid <code>User-Agent</code> header</strong> with each request</li> <li>Requests without proper authentication will return a <code>401 Unauthorized</code> error</li> </ul> <h3>Error Handling</h3> <p>The API returns consistent error codes and messages to help you troubleshoot issues. Each response includes a <code>statusCode</code> attribute indicating the outcome of your request.</p> <p><a href=\"https://docs.monei.com/api/errors\">View complete list of status codes →</a></p> <h3>Rate Limits</h3> <p>The API implements rate limiting to ensure stability. If you exceed the limits, requests will return a <code>429 Too Many Requests</code> status code.</p> # noqa: E501
6+
<p>The MONEI API is organized around <a href=\"https://en.wikipedia.org/wiki/Representational_State_Transfer\">REST</a> principles. Our API is designed to be intuitive and developer-friendly.</p> <h3>Base URL</h3> <p>All API requests should be made to:</p> <pre><code>https://api.monei.com/v1 </code></pre> <h3>Environment</h3> <p>MONEI provides two environments:</p> <ul> <li><strong>Test Environment</strong>: For development and testing without processing real payments</li> <li><strong>Live Environment</strong>: For processing real transactions in production</li> </ul> <h3>Client Libraries</h3> <p>We provide official SDKs to simplify integration:</p> <ul> <li><a href=\"https://github.com/MONEI/monei-php-sdk\">PHP SDK</a></li> <li><a href=\"https://github.com/MONEI/monei-python-sdk\">Python SDK</a></li> <li><a href=\"https://github.com/MONEI/monei-node-sdk\">Node.js SDK</a></li> <li><a href=\"https://postman.monei.com/\">Postman Collection</a></li> </ul> <p>Our SDKs handle authentication, error handling, and request formatting automatically.</p> <h3>Important Requirements</h3> <ul> <li>All API requests must be made over HTTPS</li> <li>If you are not using our official SDKs, you <strong>must provide a valid <code>User-Agent</code> header</strong> with each request</li> <li>Requests without proper authentication will return a <code>401 Unauthorized</code> error</li> </ul> <h3>Error Handling</h3> <p>The API returns consistent error codes and messages to help you troubleshoot issues. Each response includes a <code>statusCode</code> attribute indicating the outcome of your request.</p> <p><a href=\"https://docs.monei.com/api/errors\">View complete list of status codes →</a></p> <h3>Rate Limits</h3> <p>The API implements rate limiting to ensure stability. If you exceed the limits, requests will return a <code>429 Too Many Requests</code> status code.</p> # noqa: E501
77
8-
The version of the OpenAPI document: 1.5.0
9-
Generated by: https://openapi-generator.tech
8+
The version of the OpenAPI document: 1.5.0
9+
Generated by: https://openapi-generator.tech
1010
"""
1111

1212

@@ -25,5 +25,6 @@
2525
from Monei.exceptions import ApiValueError
2626
from Monei.exceptions import ApiKeyError
2727
from Monei.exceptions import ApiException
28-
# import custom MoneiClient
28+
29+
# Import MoneiClient at the end to avoid circular imports
2930
from Monei.monei_client import MoneiClient

Monei/monei_client.py

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,96 @@
22
import hmac
33
import hashlib
44

5-
from Monei import Configuration, ApiClient, PaymentsApi, ApiException, SubscriptionsApi, ApplePayDomainApi, __version__
5+
# Import specific modules instead of importing from Monei
6+
from Monei.configuration import Configuration
7+
from Monei.api_client import ApiClient
8+
from Monei.exceptions import ApiException
9+
from Monei.api.payments_api import PaymentsApi
10+
from Monei.api.subscriptions_api import SubscriptionsApi
11+
from Monei.api.apple_pay_domain_api import ApplePayDomainApi
12+
import Monei
13+
14+
15+
DEFAULT_USER_AGENT = f"MONEI/Python/{Monei.__version__}"
616

717

818
class MoneiClient(object):
919
_default = None
1020

11-
def __init__(self, api_key=None, config=None):
21+
def __init__(self, api_key=None, config=None, account_id=None, user_agent=None):
22+
"""Initialize the MONEI client
1223
24+
Args:
25+
api_key (str): Your MONEI API key
26+
config (Configuration, optional): Custom configuration
27+
account_id (str, optional): The merchant's account ID to act on behalf of
28+
user_agent (str, optional): Custom User-Agent string
29+
"""
1330
self.api_key = api_key
31+
self.account_id = account_id
32+
self.user_agent = user_agent or DEFAULT_USER_AGENT
1433

1534
self.config = config if config else Configuration()
1635

17-
self.config.api_key = {
18-
'Authorization': api_key
19-
}
36+
self.config.api_key = {"Authorization": api_key}
2037

2138
# Enter a context with an instance of the API client
2239
with ApiClient(self.config) as api_client:
23-
api_client.user_agent = "MONEI/Python/" + __version__
40+
# Set user agent
41+
api_client.user_agent = self.user_agent
42+
43+
# Set account ID if provided
44+
if self.account_id:
45+
# Validate that a custom user agent is set when using account ID
46+
if self.user_agent == DEFAULT_USER_AGENT:
47+
raise ApiException(
48+
status=400, reason="User-Agent must be provided when using Account ID"
49+
)
50+
api_client.set_default_header("MONEI-Account-ID", self.account_id)
51+
52+
# Initialize API instances
2453
self.Payments = PaymentsApi(api_client)
2554
self.Subscriptions = SubscriptionsApi(api_client)
2655
self.ApplePayDomain = ApplePayDomainApi(api_client)
2756

57+
# Store the api_client for later use
58+
self._api_client = api_client
59+
2860
# aliases
2961
self.payments = self.Payments
3062

63+
def set_account_id(self, account_id):
64+
"""Set the account ID to act on behalf of a merchant
65+
66+
Args:
67+
account_id (str): The merchant's account ID
68+
69+
Raises:
70+
ApiException: If trying to set account_id with default User-Agent
71+
"""
72+
# If setting accountId and using default User-Agent
73+
if account_id and self.user_agent == DEFAULT_USER_AGENT:
74+
raise ApiException(status=400, reason="User-Agent must be set before using Account ID")
75+
76+
self.account_id = account_id
77+
78+
# Update headers in api_client
79+
if account_id:
80+
self._api_client.set_default_header("MONEI-Account-ID", account_id)
81+
else:
82+
# Remove the header if account_id is None
83+
if "MONEI-Account-ID" in self._api_client.default_headers:
84+
del self._api_client.default_headers["MONEI-Account-ID"]
85+
86+
def set_user_agent(self, user_agent):
87+
"""Set a custom User-Agent header
88+
89+
Args:
90+
user_agent (str): Custom User-Agent string
91+
"""
92+
self.user_agent = user_agent
93+
self._api_client.user_agent = user_agent
94+
3195
def verify_signature(self, body, signature):
3296
"""Verifies response signature
3397
:param body: string JSON content to be verified
@@ -36,21 +100,18 @@ def verify_signature(self, body, signature):
36100
"""
37101

38102
parts_dict = {}
39-
signature_parts = signature.split(',')
103+
signature_parts = signature.split(",")
40104
for part in signature_parts:
41-
parts = part.split('=')
105+
parts = part.split("=")
42106
parts_dict[parts[0]] = parts[1]
43107

44108
calculated_hmac = hmac.new(
45-
bytes(self.api_key, 'utf-8'),
46-
msg=bytes('{}.{}'.format(parts_dict['t'], body), 'utf-8'),
47-
digestmod=hashlib.sha256
109+
bytes(self.api_key, "utf-8"),
110+
msg=bytes("{}.{}".format(parts_dict["t"], body), "utf-8"),
111+
digestmod=hashlib.sha256,
48112
).hexdigest()
49113

50-
if calculated_hmac != parts_dict['v1']:
51-
raise ApiException(
52-
status=401,
53-
reason='[401] Signature verification failed'
54-
)
114+
if calculated_hmac != parts_dict["v1"]:
115+
raise ApiException(status=401, reason="[401] Signature verification failed")
55116

56117
return json.loads(body)

0 commit comments

Comments
 (0)