Skip to content

Commit d64b627

Browse files
Merge branch 'Mangopay:master' into master
2 parents 1e9c30e + bfcc550 commit d64b627

31 files changed

+2072
-193
lines changed

CHANGELOG.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,158 @@
1+
## [3.50.0] - 2025-10-01
2+
### Added
3+
- [Verification of Payee (VOP)](https://docs.mangopay.com/guides/vop/recipients-payouts) API response fields (`RecipientVerificationOfPayee` and sub-properties) on the endpoints [GET View a Recipient](https://docs.mangopay.com/api-reference/recipients/view-recipient), [POST Create a Recipient](https://docs.mangopay.com/api-reference/recipients/create-recipient), [POST Create a Payout](https://docs.mangopay.com/api-reference/payouts/create-payout) ([API release note](https://docs.mangopay.com/release-notes/api/2025-09-30), #445)
4+
- Support for the [POST Cancel an Intent](https://docs.mangopay.com/api-reference/intents/cancel-intent) endpoint for [Echo](https://docs.mangopay.com/guides/echo), Mangopay's solution for platforms working with another third-party PSP for funds acquisition (#453)
5+
- Support for [POST Submit data for a PayPal PayIn](https://docs.mangopay.com/api-reference/paypal/submit-data-paypal-payin) endpoint (#450)
6+
7+
## [3.49.4] - 2025-09-23
8+
### Added
9+
- Webhook event types for [Echo](https://docs.mangopay.com/guides/echo), Mangopay's solution for third-party PSP integrations: `INTENT_AUTHORIZED`,`INTENT_CAPTURED`,`INTENT_REFUNDED`,`INTENT_REFUND_REVERSED`,`INTENT_DISPUTE_CREATED`,`INTENT_DISPUTE_DEFENDED`,`INTENT_DISPUTE_WON`,`INTENT_DISPUTE_LOST`,`INTENT_SETTLED_NOT_PAID`,`INTENT_PAID`,`SPLIT_CREATED`,`SPLIT_PENDING_FUNDS_RECEPTION`,`SPLIT_AVAILABLE`,`SPLIT_REJECTED`,`SPLIT_REVERSED` #448
10+
- Support for `VirtualAccountPurpose` on Banking Alias object #451
11+
12+
## [3.49.3] - 2025-09-08
13+
### Added
14+
- Support for `ProfilingAttemptReference` on all payment methods
15+
16+
## [3.49.2] - 2025-09-03
17+
### Added
18+
- Support for missing fields on TransferRefund #444 (thank you @obarahona10 #377)
19+
20+
### Changed
21+
- Casing of 3 fields to harmonise on snake_case #443 ⚠️ **Breaking change** for Conversion `quote_Id`, Document(KYC) `processed_date`, and Ubo `is_active` (thanks @samitnuk #268)
22+
- OAuth token refresh buffer before expiry updated to 30s #446
23+
- Updated testing library to pynose (thank you @nandoks #441)
24+
25+
### Fixed
26+
- Tests
27+
28+
## [3.49.1] - 2025-08-14
29+
### Added
30+
- Support for [POST Create a Quoted Conversion between Client Wallets](https://docs.mangopay.com/api-reference/conversions/create-quoted-conversion-client-wallets) and [POST Create an Instant Conversion between Client Wallets](https://docs.mangopay.com/api-reference/conversions/create-instant-conversion-client-wallets) #437
31+
- Support for [POST Create a Bank Wire to the Repudiation Wallet](https://docs.mangopay.com/api-reference/dispute-settlement/create-bank-wire-payin-to-repudiation-wallet) #438
32+
- Support for [GET List Disputes pending settlement](https://docs.mangopay.com/api-reference/disputes/list-disputes-settlement) #439
33+
34+
## [3.49.0] - 2025-08-07
35+
### Added
36+
Support for new Splits endpoints for Echo (#434, [API release note](https://docs.mangopay.com/release-notes/api/2025-07-16)):
37+
- [PUT Update a Split of an Intent](https://docs.mangopay.com/api-reference/intents/update-intent-split)
38+
- [POST Execute a Split of an Intent](https://docs.mangopay.com/api-reference/intents/execute-intent-split)
39+
- [POST Reverse the Split of an Intent](https://docs.mangopay.com/api-reference/intents/reverse-intent-split)
40+
- [GET View a Split of an Intent](https://docs.mangopay.com/api-reference/intents/view-intent-split)
41+
42+
New `ReportTypes` for Echo (#435, [API release note](https://docs.mangopay.com/release-notes/api/2025-08-06))):
43+
- `ECHO_INTENT`
44+
- `ECHO_INTENT_ACTION`
45+
- `ECHO_SETTLEMENT`
46+
- `ECHO_SPLIT`
47+
48+
## [3.48.1] - 2025-07-28
49+
### Added
50+
- `Sku` parameter on LineItem, for [Klarna PayIns](https://docs.mangopay.com/api-reference/klarna/create-klarna-payin)
51+
- handle new endpoint [View supported banks for Pay by Bank](https://docs.mangopay.com/api-reference/pay-by-bank/view-supported-banks-pay-by-bank), to enable presentation of banks to user before Pay by Bank payment request
52+
53+
## [3.48.0] - 2025-07-18
54+
### Added
55+
Endpoints for [Mangopay Echo](https://docs.mangopay.com/guides/echo), a solution for platforms working with another third-party PSP for funds acquisition (including via the Mirakl Connector) #429 :
56+
- [POST Create an Intent](https://docs.mangopay.com/api-reference/intents/create-intent)
57+
- [GET View an Intent](https://docs.mangopay.com/api-reference/intents/view-intent)
58+
- [POST Create a Capture for an Intent](https://docs.mangopay.com/api-reference/intents/create-intent-capture)
59+
- [POST Create a Settlement](https://docs.mangopay.com/api-reference/settlements/create-settlement)
60+
- [PUT Update a Settlement](https://docs.mangopay.com/api-reference/settlements/update-settlement)
61+
- [GET View a Settlement](https://docs.mangopay.com/api-reference/settlements/view-settlement)
62+
- [POST Create a Split of an Intent](https://docs.mangopay.com/api-reference/intents/create-intent-split)
63+
64+
## [3.47.0] - 2025-07-02
65+
### Added
66+
- New endpoint [POST Create a Bizum PayIn](https://docs.mangopay.com/api-reference/bizum/create-bizum-payin)
67+
- New webhook event types for SCA enrollment ([API release note](https://docs.mangopay.com/release-notes/api/2025-06-23)), note that these are triggered on enrollment not authentication:
68+
- `SCA_ENROLLMENT_SUCCEEDED`
69+
- `SCA_ENROLLMENT_FAILED`
70+
- `SCA_ENROLLMENT_EXPIRED`
71+
- New webhook event types for `UserCategory` change ([API release note](https://docs.mangopay.com/release-notes/api/2025-06-23) ):
72+
- `USER_CATEGORY_UPDATED_TO_OWNER`
73+
- `USER_CATEGORY_UPDATED_TO_PAYER`
74+
- `USER_CATEGORY_UPDATED_TO_PLATFORM`
75+
- Support for `PLATFORM` value to `UserCategory` enum
76+
- Support for [GET List Transactions for a Card Fingerprint](https://docs.mangopay.com/api-reference/transactions/list-transactions-card-fingerprint)
77+
- Support for [GET List Transactions for a Dispute](https://docs.mangopay.com/api-reference/transactions/list-transactions-dispute)
78+
79+
## [3.46.1] - 2025-06-16
80+
81+
### Added
82+
- [US and CA virtual accounts](https://docs.mangopay.com/release-notes/api/2025-06-12) for local pay-in collection
83+
84+
## [3.46.0] - 2025-06-10
85+
### Added
86+
87+
Endpoints for [new Reporting Service](https://docs.mangopay.com/release-notes/api/2025-06-05) feature:
88+
- [POST Create a Report](https://docs.mangopay.com/api-reference/reporting/create-report)
89+
- [GET View a Report](https://docs.mangopay.com/api-reference/reporting/view-report)
90+
- [GET List all Reports](https://docs.mangopay.com/api-reference/reporting/list-reports)
91+
92+
Webhook [event types](url) for new Reporting Service:
93+
- `REPORT_GENERATED`
94+
- `REPORT_FAILED`
95+
96+
Support for [GET List Disputes for a PayIn](https://docs.mangopay.com/api-reference/disputes/list-disputes-payin) endpoint.
97+
98+
## [3.45.1] - 2025-06-06
99+
### Added
100+
- Support for `RecipientScope` query parameter on [GET List Recipients for a User](https://docs.mangopay.com/api-reference/recipients/list-recipients-user)
101+
- [POST Validate the format of User data](https://docs.mangopay.com/api-reference/user-data-format/validate-user-data-format)
102+
103+
### Fixed
104+
- `Status` enum value on Identity Verification object changed from `OUTDATED` to `OUT_OF_DATE`
105+
106+
## [3.45.0] - 2025-05-23
107+
### Added
108+
109+
Event types for [user account webhooks](https://docs.mangopay.com//webhooks/event-types#user-account), relevant to [SCA enrollment in user endpoints](https://docs.mangopay.com/guides/sca/users#user-status) and account closure:
110+
- `USER_ACCOUNT_VALIDATION_ASKED`
111+
- `USER_ACCOUNT_ACTIVATED`
112+
- `USER_ACCOUNT_CLOSED`
113+
114+
Event types for [instant and quoted FX conversions](https://docs.mangopay.com//webhooks/event-types#fx-conversions):
115+
- `INSTANT_CONVERSION_CREATED`
116+
- `INSTANT_CONVERSION_SUCCEEDED`
117+
- `INSTANT_CONVERSION_FAILED`
118+
- `QUOTED_CONVERSION_CREATED`
119+
- `QUOTED_CONVERSION_SUCCEEDED`
120+
- `QUOTED_CONVERSION_FAILED`
121+
122+
Support for [30-day deposit preauthorization](https://docs.mangopay.com/guides/payment-methods/card/deposit-preauthorization) features:
123+
- [POST Create a Deposit Preauthorized PayIn prior to complement](https://docs.mangopay.com/api-reference/deposit-preauthorizations/create-deposit-preauthorized-payin-prior-to-complement)
124+
- [POST Create a Deposit Preauthorized PayIn complement](https://docs.mangopay.com/api-reference/deposit-preauthorizations/create-deposit-preauthorized-payin-complement)
125+
- `NO_SHOW_REQUESTED` on `updateDeposit` method for [PUT Cancel a Deposit Preauthorization or request a no-show](https://docs.mangopay.com/api-reference/deposit-preauthorizations/cancel-deposit-preauthorization-request-no-show)
126+
- [GET View a PayIn (Deposit Preauthorized Card](https://docs.mangopay.com/api-reference/deposit-preauthorizations/view-payin-deposit-preauthorized)
127+
- [GET List Transactions for a Deposit Preauthorization](https://docs.mangopay.com/api-reference/transactions/list-transactions-deposit-preauthorization)
128+
129+
### Fixed
130+
131+
- Regression on User-Agent header SDK version number
132+
133+
## [3.44.0] - 2025-05-14
134+
### Added and refined
135+
136+
#### Hosted KYC/KYB endpoints
137+
138+
The following endpoints have been refined following the beta phase, and are now generally available:
139+
- [POST Create an IDV Session](https://docs.mangopay.com/api-reference/idv-sessions/create-idv-session) (no changes)
140+
- [GET View an IDV Session](https://docs.mangopay.com/api-reference/idv-sessions/view-idv-session) (includes `Checks` in response)
141+
- [GET List IDV Sessions for a User](https://docs.mangopay.com/api-reference/idv-sessions/list-idv-sessions-user) (new endpoint)
142+
143+
The previously available endpoint GET View Checks for an IDV Session has been removed (as Checks were integrated into the GET by ID).
144+
145+
See the [guide](https://docs.mangopay.com/guides/users/verification/hosted) for more details.
146+
147+
#### Recipients
148+
149+
The `Country` property has been added to [Recipients](https://docs.mangopay.com/guides/sca/recipients), as a required query parameter on [GET View the schema for a Recipient](https://docs.mangopay.com/api-reference/recipients/view-recipient-schema) and as a required body parameter on [POST Validate data for a Recipient](https://docs.mangopay.com/api-reference/recipients/validate-recipient-data) and [POST Create a Recipient](https://docs.mangopay.com/api-reference/recipients/create-recipient).
150+
151+
### Added
152+
153+
- [GET List Deposit Preauthorizations for a Card](https://docs.mangopay.com/api-reference/deposit-preauthorizations/list-deposit-preauthorizations-card)
154+
- [GET List Deposit Preauthorizations for a User](https://docs.mangopay.com/api-reference/deposit-preauthorizations/list-deposit-preauthorizations-user)
155+
1156
## [3.43.0] - 2025-04-29
2157
### Added
3158

mangopay/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
package_version = None
1111
try:
12-
with open('../setup.py', 'r') as f:
12+
with open('./setup.py', 'r') as f:
1313
for line in f:
1414
if line.startswith(' version'):
1515
package_version = line.split('=')[1].replace("'", "").replace(",", "").replace("\n", "")

mangopay/api.py

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,16 @@ def set_rate_limit(self, rate_limit):
6060
def get_rate_limits(self):
6161
return rate_limits
6262

63-
def request(self, method, url, data=None, idempotency_key=None, oauth_request=False, without_client_id=False, **params):
64-
return self.custom_request(method, url, data, idempotency_key, oauth_request, True, without_client_id, **params)
63+
def request(self, method, url, data=None, idempotency_key=None, oauth_request=False, without_client_id=False,
64+
is_v3=False, **params):
65+
return self.custom_request(method, url, data, idempotency_key, oauth_request, True,
66+
without_client_id, is_v3, **params)
67+
68+
def multipart_request(self, method, url, file, file_name, idempotency_key=None, oauth_request=False, is_v3=False):
69+
return self.custom_multipart_request(method, url, file, file_name, idempotency_key, oauth_request, is_v3)
6570

6671
def custom_request(self, method, url, data=None, idempotency_key=None, oauth_request=False,
67-
is_mangopay_request=False, without_client_id=False, **params):
72+
is_mangopay_request=False, without_client_id=False, is_v3=False, **params):
6873
params = params or {}
6974

7075
headers = {}
@@ -102,6 +107,9 @@ def custom_request(self, method, url, data=None, idempotency_key=None, oauth_req
102107
else:
103108
url = '%s?%s' % (url, encoded_params)
104109

110+
if is_v3:
111+
url = url.replace('v2.01', 'V3.0')
112+
105113
if data or data == {}:
106114
# truncated_data = truncatechars(copy.copy(data))
107115

@@ -182,6 +190,93 @@ def custom_request(self, method, url, data=None, idempotency_key=None, oauth_req
182190
else:
183191
self._create_decodeerror(result, url=url)
184192

193+
def custom_multipart_request(self, method, url, file, file_name, idempotency_key=None, oauth_request=False, is_v3=False):
194+
if not isinstance(file, bytes):
195+
raise TypeError("The 'file' parameter must be of type 'bytes'.")
196+
197+
headers = {'User-Agent': 'Mangopay-SDK/' + str(
198+
mangopay.package_version) + ' (Python/' + platform.python_version() + ')'}
199+
200+
if oauth_request:
201+
headers['Authorization'] = self.auth_manager.basic_token()
202+
else:
203+
headers['Authorization'] = self.auth_manager.get_token()
204+
205+
if idempotency_key:
206+
headers['Idempotency-Key'] = idempotency_key
207+
208+
if self.uk_header_flag:
209+
headers['x-tenant-id'] = 'uk'
210+
211+
if oauth_request:
212+
url = self.api_url + url
213+
else:
214+
url = self._absolute_url(url, '')
215+
216+
if is_v3:
217+
url = url.replace('v2.01', 'V3.0')
218+
219+
files = {'file': (file_name, file)}
220+
221+
logger.debug('DATA[IN -> %s]\n\t- headers: %s\n\t- file: %s', url, headers, 'provided' if file else 'none')
222+
ts = time.time()
223+
224+
request_started.send(url=url, data=None, headers=headers, method=method)
225+
226+
try:
227+
result = requests_session.request(method, url,
228+
files=files,
229+
headers=headers,
230+
timeout=self.timeout,
231+
proxies=self.proxies)
232+
except ConnectionError as e:
233+
msg = f'{type(e).__name__}: {e}' if str(e) else type(e).__name__
234+
reraise_as(APIError(msg))
235+
236+
except Timeout as e:
237+
msg = f'{type(e).__name__}: {e}' if str(e) else type(e).__name__
238+
reraise_as(APIError(msg))
239+
240+
laps = time.time() - ts
241+
242+
request_finished.send(url=url,
243+
data=None,
244+
headers=headers,
245+
method=method,
246+
result=result,
247+
laps=laps)
248+
249+
logger.debug('DATA[OUT -> %s][%2.3f seconds]\n\t- status_code: %s\n\t- headers: %s\n\t- content: %s',
250+
url,
251+
laps,
252+
result.status_code,
253+
result.headers,
254+
result.text if hasattr(result, 'text') else result.content
255+
)
256+
257+
self.read_response_headers(result.headers)
258+
259+
if result.status_code not in (requests.codes.ok, requests.codes.not_found,
260+
requests.codes.created, requests.codes.accepted,
261+
requests.codes.no_content):
262+
self._create_apierror(result, url=url, data=None, method=method)
263+
elif result.status_code == requests.codes.no_content or (
264+
result.status_code == requests.codes.ok and result.content == b''):
265+
return result, None
266+
else:
267+
if result.content:
268+
try:
269+
content = result.content
270+
if six.PY3:
271+
content = content.decode('utf-8')
272+
return result, json.loads(content)
273+
except ValueError:
274+
if result.content.startswith(b'data='):
275+
return result.content
276+
self._create_decodeerror(result, url=url)
277+
else:
278+
self._create_decodeerror(result, url=url)
279+
185280
def read_response_headers(self, headers):
186281
rate_limit_reset = headers.get('x-ratelimit-reset')
187282
rate_limit_remaining = headers.get('x-ratelimit-remaining')

mangopay/auth.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import base64
22
import hashlib
33
import json
4-
import stat
5-
64
import os
5+
import stat
76
import tempfile
7+
import time
88

99
import six
10-
import time
1110

1211
import mangopay
1312
from mangopay.exceptions import AuthenticationError
@@ -90,7 +89,7 @@ def get_token(self):
9089
token = auth_result[1]
9190
else:
9291
return None
93-
token['timestamp'] = time.time() + (int(token['expires_in']) - 10)
92+
token['timestamp'] = time.time() + (int(token['expires_in']) - 30)
9493
self.set_token(token)
9594

9695
return token['token_type'] + ' ' + token['access_token']

0 commit comments

Comments
 (0)