nuvei 1.0.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.
- nuvei-1.0.0/LICENSE +21 -0
- nuvei-1.0.0/PKG-INFO +598 -0
- nuvei-1.0.0/README.md +563 -0
- nuvei-1.0.0/nuvei/__init__.py +71 -0
- nuvei-1.0.0/nuvei/checksum.py +62 -0
- nuvei-1.0.0/nuvei/client.py +290 -0
- nuvei-1.0.0/nuvei/config.py +42 -0
- nuvei-1.0.0/nuvei/constants.py +45 -0
- nuvei-1.0.0/nuvei/exceptions.py +52 -0
- nuvei-1.0.0/nuvei/py.typed +0 -0
- nuvei-1.0.0/nuvei/services/__init__.py +1 -0
- nuvei-1.0.0/nuvei/services/advanced_apm.py +114 -0
- nuvei-1.0.0/nuvei/services/authentication.py +43 -0
- nuvei-1.0.0/nuvei/services/card_operations.py +61 -0
- nuvei-1.0.0/nuvei/services/financial.py +146 -0
- nuvei-1.0.0/nuvei/services/orders.py +84 -0
- nuvei-1.0.0/nuvei/services/payments.py +158 -0
- nuvei-1.0.0/nuvei/services/subscriptions.py +222 -0
- nuvei-1.0.0/nuvei/services/three_d_secure.py +95 -0
- nuvei-1.0.0/nuvei/services/user_payment_options.py +251 -0
- nuvei-1.0.0/nuvei/services/users.py +84 -0
- nuvei-1.0.0/nuvei/webhook.py +122 -0
- nuvei-1.0.0/nuvei.egg-info/PKG-INFO +598 -0
- nuvei-1.0.0/nuvei.egg-info/SOURCES.txt +44 -0
- nuvei-1.0.0/nuvei.egg-info/dependency_links.txt +1 -0
- nuvei-1.0.0/nuvei.egg-info/requires.txt +9 -0
- nuvei-1.0.0/nuvei.egg-info/top_level.txt +1 -0
- nuvei-1.0.0/pyproject.toml +65 -0
- nuvei-1.0.0/setup.cfg +4 -0
- nuvei-1.0.0/tests/test_async_client.py +123 -0
- nuvei-1.0.0/tests/test_checksum.py +76 -0
- nuvei-1.0.0/tests/test_checksum_integration.py +302 -0
- nuvei-1.0.0/tests/test_client.py +99 -0
- nuvei-1.0.0/tests/test_config.py +31 -0
- nuvei-1.0.0/tests/test_package.py +76 -0
- nuvei-1.0.0/tests/test_services_advanced_apm.py +61 -0
- nuvei-1.0.0/tests/test_services_authentication.py +43 -0
- nuvei-1.0.0/tests/test_services_card_operations.py +58 -0
- nuvei-1.0.0/tests/test_services_financial.py +120 -0
- nuvei-1.0.0/tests/test_services_orders.py +76 -0
- nuvei-1.0.0/tests/test_services_payments.py +124 -0
- nuvei-1.0.0/tests/test_services_subscriptions.py +168 -0
- nuvei-1.0.0/tests/test_services_three_d_secure.py +78 -0
- nuvei-1.0.0/tests/test_services_upo.py +193 -0
- nuvei-1.0.0/tests/test_services_users.py +69 -0
- nuvei-1.0.0/tests/test_webhook.py +71 -0
nuvei-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Krishan Jangid
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
nuvei-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nuvei
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Nuvei REST API v1.0 SDK for Python — payment processing, 3D Secure, subscriptions, and more.
|
|
5
|
+
Author: Krishan Jangid
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/krishanjangid/nuvei-python
|
|
8
|
+
Project-URL: Documentation, https://docs.nuvei.com
|
|
9
|
+
Project-URL: Repository, https://github.com/krishanjangid/nuvei-python
|
|
10
|
+
Project-URL: Changelog, https://github.com/krishanjangid/nuvei-python/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: nuvei,payment,gateway,credit-card,psp,3d-secure,subscription
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: Office/Business :: Financial :: Point-Of-Sale
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: httpx<1.0,>=0.27.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-httpx>=0.30; extra == "dev"
|
|
31
|
+
Requires-Dist: respx>=0.21; extra == "dev"
|
|
32
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
33
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# Nuvei Python SDK
|
|
37
|
+
|
|
38
|
+
A lightweight Python wrapper for the **Nuvei REST API v1.0** — authentication, payments, 3D Secure, financial operations, subscriptions, user & payment option management, all in one package.
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
- **Full API v1.0 coverage** — authentication, payments, financial operations, 3D Secure, card operations, subscriptions, user & UPO management, advanced APM
|
|
43
|
+
- **Sync and async clients** — powered by `httpx`
|
|
44
|
+
- **Automatic checksum calculation** — SHA-256 (default) or MD5
|
|
45
|
+
- **Webhook/DMN verification** — validate `advanceResponseChecksum` on incoming notifications
|
|
46
|
+
- **Type-annotated** — full type hints with `py.typed` marker (PEP 561)
|
|
47
|
+
- **Minimal dependencies** — only `httpx`
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install nuvei
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or for development:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install -e ".[dev]"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
### Synchronous Usage
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from nuvei import Nuvei
|
|
67
|
+
|
|
68
|
+
client = Nuvei(
|
|
69
|
+
merchant_id="your_merchant_id",
|
|
70
|
+
merchant_site_id="your_site_id",
|
|
71
|
+
merchant_secret_key="your_secret_key",
|
|
72
|
+
environment="test", # "prod", "test", "int", "qa"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# 1. Get a session token
|
|
76
|
+
session = client.get_session_token()
|
|
77
|
+
token = session["sessionToken"]
|
|
78
|
+
|
|
79
|
+
# 2. Open an order
|
|
80
|
+
order = client.open_order(amount="10.00", currency="USD")
|
|
81
|
+
order_token = order["sessionToken"]
|
|
82
|
+
|
|
83
|
+
# 3. Process a payment
|
|
84
|
+
result = client.payments.payment(
|
|
85
|
+
sessionToken=order_token,
|
|
86
|
+
amount="10.00",
|
|
87
|
+
currency="USD",
|
|
88
|
+
paymentOption={
|
|
89
|
+
"card": {
|
|
90
|
+
"cardNumber": "4111111111111111",
|
|
91
|
+
"cardHolderName": "John Doe",
|
|
92
|
+
"expirationMonth": "12",
|
|
93
|
+
"expirationYear": "2028",
|
|
94
|
+
"CVV": "217",
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
)
|
|
98
|
+
print(result["transactionId"], result["status"])
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Async Usage
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
import asyncio
|
|
105
|
+
from nuvei import AsyncNuvei
|
|
106
|
+
|
|
107
|
+
async def main():
|
|
108
|
+
async with AsyncNuvei(
|
|
109
|
+
merchant_id="your_merchant_id",
|
|
110
|
+
merchant_site_id="your_site_id",
|
|
111
|
+
merchant_secret_key="your_secret_key",
|
|
112
|
+
environment="test",
|
|
113
|
+
) as client:
|
|
114
|
+
session = await client.get_session_token()
|
|
115
|
+
print(session["sessionToken"])
|
|
116
|
+
|
|
117
|
+
asyncio.run(main())
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Service Modules
|
|
121
|
+
|
|
122
|
+
Access API endpoints through organized service namespaces:
|
|
123
|
+
|
|
124
|
+
| Service | Accessor | Endpoints |
|
|
125
|
+
|---------|----------|-----------|
|
|
126
|
+
| **Authentication** | `client.authentication` | `get_session_token` |
|
|
127
|
+
| **Orders** | `client.orders` | `open_order`, `update_order`, `get_order_details` |
|
|
128
|
+
| **Payments** | `client.payments` | `payment`, `payment_cc`, `payment_apm`, `init_payment`, `get_payment_status`, `account_capture`, `get_mcp_rates`, `get_dcc_details` |
|
|
129
|
+
| **Financial** | `client.financial` | `settle_transaction`, `refund_transaction`, `void_transaction`, `payout`, `get_payout_status` |
|
|
130
|
+
| **3D Secure** | `client.three_d_secure` | `authorize3d`, `verify3d`, `dynamic3d` |
|
|
131
|
+
| **Card Operations** | `client.card_operations` | `card_tokenization`, `get_card_details` |
|
|
132
|
+
| **Users** | `client.users` | `create_user`, `update_user`, `get_user_details` |
|
|
133
|
+
| **UPOs** | `client.user_payment_options` | `add_upo_credit_card`, `add_upo_credit_card_by_temp_token`, `add_upo_credit_card_by_token`, `add_upo_apm`, `edit_upo_cc`, `edit_upo_apm`, `get_user_upos`, `delete_upo`, `suspend_upo`, `enable_upo`, `get_merchant_payment_methods` |
|
|
134
|
+
| **Subscriptions** | `client.subscriptions` | `create_plan`, `edit_plan`, `get_plans_list`, `create_subscription`, `edit_subscription`, `cancel_subscription`, `get_subscriptions_list`, `get_subscription_plans` |
|
|
135
|
+
| **Advanced APM** | `client.advanced_apm` | `add_bank_account`, `enroll_account`, `fund_account`, `get_account_details`, `get_document_url` |
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Integration Flows
|
|
140
|
+
|
|
141
|
+
### Flow 1: Simple Payment (Sale)
|
|
142
|
+
|
|
143
|
+
The most common flow — charge a customer immediately.
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from nuvei import Nuvei
|
|
147
|
+
|
|
148
|
+
client = Nuvei(
|
|
149
|
+
merchant_id="...", merchant_site_id="...",
|
|
150
|
+
merchant_secret_key="...", environment="test",
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# Step 1: Open an order
|
|
154
|
+
order = client.open_order(amount="29.99", currency="USD")
|
|
155
|
+
|
|
156
|
+
# Step 2: Process the payment
|
|
157
|
+
result = client.payments.payment(
|
|
158
|
+
sessionToken=order["sessionToken"],
|
|
159
|
+
amount="29.99",
|
|
160
|
+
currency="USD",
|
|
161
|
+
transactionType="Sale",
|
|
162
|
+
paymentOption={
|
|
163
|
+
"card": {
|
|
164
|
+
"cardNumber": "4111111111111111",
|
|
165
|
+
"cardHolderName": "Jane Smith",
|
|
166
|
+
"expirationMonth": "12",
|
|
167
|
+
"expirationYear": "2028",
|
|
168
|
+
"CVV": "217",
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
deviceDetails={"ipAddress": "192.168.1.1"},
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
if result["status"] == "SUCCESS" and result["transactionStatus"] == "APPROVED":
|
|
175
|
+
print(f"Payment approved! Transaction ID: {result['transactionId']}")
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Flow 2: Auth and Settle
|
|
179
|
+
|
|
180
|
+
Authorize first, then settle (capture) later — common for e-commerce.
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
# Step 1: Open order
|
|
184
|
+
order = client.open_order(amount="100.00", currency="USD")
|
|
185
|
+
|
|
186
|
+
# Step 2: Authorize (hold funds, don't charge yet)
|
|
187
|
+
auth = client.payments.payment(
|
|
188
|
+
sessionToken=order["sessionToken"],
|
|
189
|
+
amount="100.00",
|
|
190
|
+
currency="USD",
|
|
191
|
+
transactionType="Auth",
|
|
192
|
+
paymentOption={
|
|
193
|
+
"card": {
|
|
194
|
+
"cardNumber": "4111111111111111",
|
|
195
|
+
"cardHolderName": "John Doe",
|
|
196
|
+
"expirationMonth": "12",
|
|
197
|
+
"expirationYear": "2028",
|
|
198
|
+
"CVV": "217",
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# Step 3: Settle (capture) — can be full or partial amount
|
|
204
|
+
settle = client.financial.settle_transaction(
|
|
205
|
+
relatedTransactionId=auth["transactionId"],
|
|
206
|
+
amount="100.00", # or a partial amount like "50.00"
|
|
207
|
+
currency="USD",
|
|
208
|
+
authCode=auth["authCode"],
|
|
209
|
+
)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Flow 3: Payment with 3D Secure (3DS 2.0)
|
|
213
|
+
|
|
214
|
+
Full 3DS flow for liability-shifted payments.
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
# Step 1: Open order
|
|
218
|
+
order = client.open_order(amount="50.00", currency="USD")
|
|
219
|
+
|
|
220
|
+
# Step 2: Init payment — check 3DS support
|
|
221
|
+
init = client.payments.init_payment(
|
|
222
|
+
sessionToken=order["sessionToken"],
|
|
223
|
+
amount="50.00",
|
|
224
|
+
currency="USD",
|
|
225
|
+
paymentOption={
|
|
226
|
+
"card": {
|
|
227
|
+
"cardNumber": "4000027891380961", # 3DS test card
|
|
228
|
+
"cardHolderName": "CL-BRW1",
|
|
229
|
+
"expirationMonth": "12",
|
|
230
|
+
"expirationYear": "2028",
|
|
231
|
+
"CVV": "217",
|
|
232
|
+
"threeD": {
|
|
233
|
+
"methodNotificationUrl": "https://your-site.com/3ds-notify",
|
|
234
|
+
},
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
# Step 3: Handle 3DS fingerprinting (client-side iframe)
|
|
240
|
+
# Render the threeD data from init["paymentOption"]["card"]["threeD"]
|
|
241
|
+
|
|
242
|
+
# Step 4: Authorize 3D (after challenge completion)
|
|
243
|
+
auth3d = client.three_d_secure.authorize3d(
|
|
244
|
+
sessionToken=order["sessionToken"],
|
|
245
|
+
amount="50.00",
|
|
246
|
+
currency="USD",
|
|
247
|
+
paymentOption={
|
|
248
|
+
"card": {
|
|
249
|
+
"threeD": {
|
|
250
|
+
# Include challenge result data here
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
relatedTransactionId=init["transactionId"],
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# Step 5: Final payment with liability shift
|
|
258
|
+
payment = client.payments.payment(
|
|
259
|
+
sessionToken=order["sessionToken"],
|
|
260
|
+
amount="50.00",
|
|
261
|
+
currency="USD",
|
|
262
|
+
transactionType="Sale",
|
|
263
|
+
relatedTransactionId=auth3d["transactionId"],
|
|
264
|
+
paymentOption={
|
|
265
|
+
"card": {
|
|
266
|
+
"cardNumber": "4000027891380961",
|
|
267
|
+
"cardHolderName": "CL-BRW1",
|
|
268
|
+
"expirationMonth": "12",
|
|
269
|
+
"expirationYear": "2028",
|
|
270
|
+
"CVV": "217",
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Flow 4: Returning Customer (CIT / MIT with UPO)
|
|
277
|
+
|
|
278
|
+
Save a payment method after the first transaction, then use it for future payments.
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
# --- First-time payment: Customer-Initiated Transaction (CIT) ---
|
|
282
|
+
|
|
283
|
+
# Step 1: Create the user
|
|
284
|
+
client.users.create_user(
|
|
285
|
+
userTokenId="customer_12345",
|
|
286
|
+
countryCode="US",
|
|
287
|
+
firstName="Jane",
|
|
288
|
+
lastName="Smith",
|
|
289
|
+
email="jane@example.com",
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
# Step 2: Open order with userTokenId
|
|
293
|
+
order = client.open_order(
|
|
294
|
+
amount="49.99", currency="USD",
|
|
295
|
+
userTokenId="customer_12345",
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
# Step 3: Process first payment (card is saved automatically with userTokenId)
|
|
299
|
+
first_payment = client.payments.payment(
|
|
300
|
+
sessionToken=order["sessionToken"],
|
|
301
|
+
amount="49.99",
|
|
302
|
+
currency="USD",
|
|
303
|
+
transactionType="Sale",
|
|
304
|
+
userTokenId="customer_12345",
|
|
305
|
+
paymentOption={
|
|
306
|
+
"card": {
|
|
307
|
+
"cardNumber": "4111111111111111",
|
|
308
|
+
"cardHolderName": "Jane Smith",
|
|
309
|
+
"expirationMonth": "12",
|
|
310
|
+
"expirationYear": "2028",
|
|
311
|
+
"CVV": "217",
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
# Step 4: Get saved payment methods (UPOs)
|
|
317
|
+
upos = client.user_payment_options.get_user_upos(
|
|
318
|
+
userTokenId="customer_12345",
|
|
319
|
+
)
|
|
320
|
+
upo_id = upos["paymentMethods"][0]["userPaymentOptionId"]
|
|
321
|
+
|
|
322
|
+
# --- Future payment: Use saved UPO (CIT or MIT) ---
|
|
323
|
+
|
|
324
|
+
order2 = client.open_order(
|
|
325
|
+
amount="49.99", currency="USD",
|
|
326
|
+
userTokenId="customer_12345",
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
future_payment = client.payments.payment(
|
|
330
|
+
sessionToken=order2["sessionToken"],
|
|
331
|
+
amount="49.99",
|
|
332
|
+
currency="USD",
|
|
333
|
+
transactionType="Sale",
|
|
334
|
+
userTokenId="customer_12345",
|
|
335
|
+
paymentOption={"userPaymentOptionId": upo_id},
|
|
336
|
+
isRebilling="0", # "1" for MIT (merchant-initiated)
|
|
337
|
+
)
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Flow 5: Subscription / Rebilling
|
|
341
|
+
|
|
342
|
+
Set up automatic recurring payments.
|
|
343
|
+
|
|
344
|
+
```python
|
|
345
|
+
# Step 1: Create a plan
|
|
346
|
+
plan = client.subscriptions.create_plan(
|
|
347
|
+
name="Premium Monthly",
|
|
348
|
+
initialAmount="0.00",
|
|
349
|
+
recurringAmount="29.99",
|
|
350
|
+
currency="USD",
|
|
351
|
+
endAfter={"day": "0", "month": "12", "year": "0"},
|
|
352
|
+
startAfter={"day": "0", "month": "1", "year": "0"},
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
# Step 2: Create a subscription for the user
|
|
356
|
+
sub = client.subscriptions.create_subscription(
|
|
357
|
+
userTokenId="customer_12345",
|
|
358
|
+
planId=plan["planId"],
|
|
359
|
+
userPaymentOptionId=upo_id,
|
|
360
|
+
initialAmount="0.00",
|
|
361
|
+
recurringAmount="29.99",
|
|
362
|
+
currency="USD",
|
|
363
|
+
endAfter={"day": "0", "month": "12", "year": "0"},
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
# Step 3: List active subscriptions
|
|
367
|
+
subs = client.subscriptions.get_subscriptions_list(
|
|
368
|
+
userTokenId="customer_12345",
|
|
369
|
+
subscriptionStatus="ACTIVE",
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
# Step 4: Cancel when needed
|
|
373
|
+
client.subscriptions.cancel_subscription(
|
|
374
|
+
subscriptionId=sub["subscriptionId"],
|
|
375
|
+
)
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Flow 6: Refund
|
|
379
|
+
|
|
380
|
+
```python
|
|
381
|
+
# Full refund
|
|
382
|
+
refund = client.financial.refund_transaction(
|
|
383
|
+
relatedTransactionId="original_txn_id",
|
|
384
|
+
amount="49.99",
|
|
385
|
+
currency="USD",
|
|
386
|
+
clientUniqueId="refund-001",
|
|
387
|
+
authCode="original_auth_code",
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
# Partial refund
|
|
391
|
+
partial_refund = client.financial.refund_transaction(
|
|
392
|
+
relatedTransactionId="original_txn_id",
|
|
393
|
+
amount="10.00", # partial amount
|
|
394
|
+
currency="USD",
|
|
395
|
+
clientUniqueId="refund-002",
|
|
396
|
+
authCode="original_auth_code",
|
|
397
|
+
)
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Flow 7: Void
|
|
401
|
+
|
|
402
|
+
Cancel a transaction before settlement.
|
|
403
|
+
|
|
404
|
+
```python
|
|
405
|
+
void = client.financial.void_transaction(
|
|
406
|
+
relatedTransactionId="original_txn_id",
|
|
407
|
+
amount="49.99",
|
|
408
|
+
currency="USD",
|
|
409
|
+
authCode="original_auth_code",
|
|
410
|
+
)
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Flow 8: Payout
|
|
414
|
+
|
|
415
|
+
Send money to a payment method (credit/disbursement).
|
|
416
|
+
|
|
417
|
+
```python
|
|
418
|
+
payout = client.financial.payout(
|
|
419
|
+
userTokenId="customer_12345",
|
|
420
|
+
amount="100.00",
|
|
421
|
+
currency="USD",
|
|
422
|
+
userPaymentOption={"userPaymentOptionId": upo_id},
|
|
423
|
+
comment="Withdrawal payout",
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
# Check payout status
|
|
427
|
+
status = client.financial.get_payout_status(
|
|
428
|
+
clientRequestId=payout["clientRequestId"],
|
|
429
|
+
)
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
## Webhook (DMN) Verification
|
|
435
|
+
|
|
436
|
+
Nuvei sends Direct Merchant Notifications (DMN) to your server after transaction events. Always verify the checksum.
|
|
437
|
+
|
|
438
|
+
```python
|
|
439
|
+
from nuvei import verify_webhook
|
|
440
|
+
|
|
441
|
+
# In your webhook handler (Flask, FastAPI, Django, etc.)
|
|
442
|
+
def handle_nuvei_webhook(params: dict):
|
|
443
|
+
is_valid = verify_webhook(
|
|
444
|
+
params,
|
|
445
|
+
merchant_secret_key="your_secret_key",
|
|
446
|
+
raise_on_failure=False, # or True to raise ChecksumError
|
|
447
|
+
)
|
|
448
|
+
if is_valid:
|
|
449
|
+
txn_id = params.get("PPP_TransactionID")
|
|
450
|
+
status = params.get("Status")
|
|
451
|
+
# Process the notification...
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
For custom DMN types with different field orderings:
|
|
455
|
+
|
|
456
|
+
```python
|
|
457
|
+
from nuvei import verify_webhook_generic
|
|
458
|
+
|
|
459
|
+
verify_webhook_generic(
|
|
460
|
+
params,
|
|
461
|
+
merchant_secret_key="your_secret_key",
|
|
462
|
+
checksum_fields=["fieldA", "fieldB", "fieldC"],
|
|
463
|
+
checksum_param="advanceResponseChecksum",
|
|
464
|
+
secret_position="prefix", # or "suffix"
|
|
465
|
+
)
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## Configuration
|
|
471
|
+
|
|
472
|
+
### Hash Algorithm
|
|
473
|
+
|
|
474
|
+
```python
|
|
475
|
+
# Default is SHA-256; switch to MD5 if your account requires it
|
|
476
|
+
client = Nuvei(..., algorithm="md5")
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### Environments
|
|
480
|
+
|
|
481
|
+
| Environment | Base URL |
|
|
482
|
+
|-------------|----------|
|
|
483
|
+
| `prod` | `https://secure.safecharge.com` |
|
|
484
|
+
| `test` | `https://ppp-test.nuvei.com` |
|
|
485
|
+
| `int` | `https://ppp-test.nuvei.com` |
|
|
486
|
+
| `qa` | `https://apmtest.gate2shop.com` |
|
|
487
|
+
|
|
488
|
+
### Context Manager
|
|
489
|
+
|
|
490
|
+
```python
|
|
491
|
+
# Auto-close the HTTP client
|
|
492
|
+
with Nuvei(...) as client:
|
|
493
|
+
session = client.get_session_token()
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## Error Handling
|
|
499
|
+
|
|
500
|
+
The SDK raises specific exceptions for different failure modes:
|
|
501
|
+
|
|
502
|
+
```python
|
|
503
|
+
from nuvei import APIError, AuthenticationError, TransportError, ChecksumError
|
|
504
|
+
|
|
505
|
+
try:
|
|
506
|
+
result = client.payments.payment(...)
|
|
507
|
+
except AuthenticationError as e:
|
|
508
|
+
# Session token or credential issues
|
|
509
|
+
print(f"Auth failed: {e.reason}")
|
|
510
|
+
except APIError as e:
|
|
511
|
+
# Nuvei API returned an error
|
|
512
|
+
print(f"API error {e.err_code}: {e.reason}")
|
|
513
|
+
print(e.response_body) # full response dict
|
|
514
|
+
except TransportError as e:
|
|
515
|
+
# Network / HTTP-level errors
|
|
516
|
+
print(f"Network error: {e}")
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
### Response Handling
|
|
520
|
+
|
|
521
|
+
Every API method returns the full response dict from Nuvei. Check these fields:
|
|
522
|
+
|
|
523
|
+
| Field | Description |
|
|
524
|
+
|-------|-------------|
|
|
525
|
+
| `status` | `"SUCCESS"` or `"ERROR"` — indicates if the request was processed |
|
|
526
|
+
| `errCode` | `0` for success, non-zero for errors |
|
|
527
|
+
| `reason` | Human-readable error description |
|
|
528
|
+
| `transactionStatus` | `"APPROVED"`, `"DECLINED"`, `"PENDING"`, `"ERROR"` — actual transaction result |
|
|
529
|
+
| `transactionId` | Nuvei's unique transaction identifier |
|
|
530
|
+
| `authCode` | Authorization code from the issuer |
|
|
531
|
+
| `gwErrorCode` | Gateway-specific error code |
|
|
532
|
+
| `gwErrorReason` | Gateway-specific error description |
|
|
533
|
+
|
|
534
|
+
> **Important**: A `status: "SUCCESS"` means the request was processed — it does NOT mean the transaction was approved. Always check `transactionStatus` for the actual result.
|
|
535
|
+
|
|
536
|
+
For more details, see: [Nuvei Response Handling Guide](https://docs.nuvei.com/documentation/integration/response-handling/)
|
|
537
|
+
|
|
538
|
+
---
|
|
539
|
+
|
|
540
|
+
## Testing & Development
|
|
541
|
+
|
|
542
|
+
### Running Tests
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
pip install -e ".[dev]"
|
|
546
|
+
python -m pytest tests/ -v
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
### Testing Cards
|
|
550
|
+
|
|
551
|
+
Use these test card numbers in the **test** environment:
|
|
552
|
+
|
|
553
|
+
| Card Number | Brand | Behavior |
|
|
554
|
+
|-------------|-------|----------|
|
|
555
|
+
| `4111111111111111` | Visa | Approved |
|
|
556
|
+
| `5111111111111118` | Mastercard | Approved |
|
|
557
|
+
| `4000027891380961` | Visa | 3DS Challenge |
|
|
558
|
+
| `4000020951595032` | Visa | 3DS Frictionless |
|
|
559
|
+
| `4000023104662535` | Visa | Declined |
|
|
560
|
+
|
|
561
|
+
- **Expiry date**: Any future date (e.g. `12/2028`)
|
|
562
|
+
- **CVV**: Any 3 digits (e.g. `217`)
|
|
563
|
+
|
|
564
|
+
For the full list of testing cards, see: [Nuvei Testing Cards](https://docs.nuvei.com/documentation/integration/testing/testing-cards/)
|
|
565
|
+
|
|
566
|
+
### Testing with Postman
|
|
567
|
+
|
|
568
|
+
Nuvei provides a Postman collection for testing API calls interactively:
|
|
569
|
+
|
|
570
|
+
1. Import the Nuvei API collection into Postman
|
|
571
|
+
2. Set environment variables: `merchantId`, `merchantSiteId`, `merchantSecretKey`
|
|
572
|
+
3. Use the collection to test individual endpoints and verify responses
|
|
573
|
+
|
|
574
|
+
For details, see: [Testing APIs with Postman](https://docs.nuvei.com/documentation/integration/testing/testing-apis-with-postman/)
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## Helpful Resources
|
|
579
|
+
|
|
580
|
+
| Resource | Link |
|
|
581
|
+
|----------|------|
|
|
582
|
+
| **Nuvei API v1.0 Reference** | [Main API Docs](https://docs.nuvei.com/api/main/indexMain_v1_0.html?json#Introduction) |
|
|
583
|
+
| **Advanced API Reference** | [Advanced API Docs](https://docs.nuvei.com/api/advanced/indexAdvanced.html?json#Introduction) |
|
|
584
|
+
| **Response Handling** | [Response Handling Guide](https://docs.nuvei.com/documentation/integration/response-handling/) |
|
|
585
|
+
| **Webhooks (DMN)** | [Webhook Documentation](https://docs.nuvei.com/documentation/integration/webhooks/) |
|
|
586
|
+
| **Testing Cards** | [Testing Cards Reference](https://docs.nuvei.com/documentation/integration/testing/testing-cards/) |
|
|
587
|
+
| **Testing with Postman** | [Postman Guide](https://docs.nuvei.com/documentation/integration/testing/testing-apis-with-postman/) |
|
|
588
|
+
| **3D Secure** | [3DS Documentation](https://docs.nuvei.com/documentation/features/3d-secure/) |
|
|
589
|
+
| **Financial Operations** | [Financial Ops Guide](https://docs.nuvei.com/documentation/features/financial-operations/) |
|
|
590
|
+
| **Subscription/Rebilling** | [Subscription Docs](https://docs.nuvei.com/documentation/features/subscription-rebilling/) |
|
|
591
|
+
| **Authentication** | [Auth Documentation](https://docs.nuvei.com/documentation/features/authentication/) |
|
|
592
|
+
| **Checksum Tool** | [Online Checksum Calculator](https://docs.nuvei.com/checksum-tool/) |
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
## License
|
|
597
|
+
|
|
598
|
+
MIT
|