pypaystack2 3.1.0__tar.gz → 3.2.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.
Files changed (76) hide show
  1. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/PKG-INFO +2 -3
  2. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/README.md +1 -1
  3. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/pyproject.toml +1 -3
  4. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/_metadata.py +2 -2
  5. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/base_clients.py +3 -3
  6. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/enums.py +3 -0
  7. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/main_clients.py +38 -19
  8. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/models/__init__.py +1 -0
  9. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/models/payload_models.py +16 -0
  10. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/charge.py +23 -7
  11. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/customers.py +193 -1
  12. pypaystack2-3.2.1/src/pypaystack2/sub_clients/async_clients/direct_debits.py +91 -0
  13. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/miscellaneous.py +4 -0
  14. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/payment_pages.py +28 -4
  15. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/payment_requests.py +6 -0
  16. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/refunds.py +50 -2
  17. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/transactions.py +5 -2
  18. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/transfers.py +14 -1
  19. pypaystack2-3.2.1/src/pypaystack2/sub_clients/async_clients/virtual_terminals.py +293 -0
  20. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/charge.py +23 -7
  21. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/customers.py +193 -1
  22. pypaystack2-3.2.1/src/pypaystack2/sub_clients/sync_clients/direct_debits.py +91 -0
  23. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/miscellaneous.py +4 -0
  24. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/payment_pages.py +28 -4
  25. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/payment_requests.py +6 -0
  26. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/refunds.py +50 -2
  27. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/transactions.py +3 -0
  28. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/transfers.py +14 -1
  29. pypaystack2-3.2.1/src/pypaystack2/sub_clients/sync_clients/virtual_terminals.py +287 -0
  30. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/__init__.py +0 -0
  31. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/cli.py +0 -0
  32. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/exceptions.py +0 -0
  33. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/fees_calculation_mixin.py +0 -0
  34. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/models/response_models.py +0 -0
  35. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/py.typed +0 -0
  36. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/__init__.py +0 -0
  37. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/__init__.py +0 -0
  38. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/apple_pay.py +0 -0
  39. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/bulk_charges.py +0 -0
  40. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/dedicated_accounts.py +0 -0
  41. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/disputes.py +0 -0
  42. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/integration.py +0 -0
  43. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/plans.py +0 -0
  44. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/products.py +0 -0
  45. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/settlements.py +0 -0
  46. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/splits.py +0 -0
  47. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/subaccounts.py +0 -0
  48. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/subscriptions.py +0 -0
  49. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/terminals.py +0 -0
  50. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/transfer_recipients.py +0 -0
  51. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/transfers_control.py +0 -0
  52. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/async_clients/verification.py +0 -0
  53. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/__init__.py +0 -0
  54. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/apple_pay.py +0 -0
  55. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/bulk_charges.py +0 -0
  56. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/dedicated_accounts.py +0 -0
  57. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/disputes.py +0 -0
  58. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/integration.py +0 -0
  59. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/plans.py +0 -0
  60. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/products.py +0 -0
  61. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/settlements.py +0 -0
  62. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/splits.py +0 -0
  63. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/subaccounts.py +0 -0
  64. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/subscriptions.py +0 -0
  65. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/terminals.py +0 -0
  66. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/transfer_recipients.py +0 -0
  67. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/transfers_control.py +0 -0
  68. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/sub_clients/sync_clients/verification.py +0 -0
  69. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/types.py +0 -0
  70. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/utils.py +0 -0
  71. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/webhook/__init__.py +0 -0
  72. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/webhook/cli.py +0 -0
  73. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/webhook/enums.py +0 -0
  74. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/webhook/logging_config.py +0 -0
  75. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/webhook/models.py +0 -0
  76. {pypaystack2-3.1.0 → pypaystack2-3.2.1}/src/pypaystack2/webhook/webhook_proxy_server.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pypaystack2
3
- Version: 3.1.0
3
+ Version: 3.2.1
4
4
  Summary: A developer-friendly client library for Paystack
5
5
  Keywords: paystack-python,pypaystack,paystack,paystackapi
6
6
  Author: Gbenga Adeyi
@@ -14,7 +14,6 @@ Requires-Dist: pydantic>=2.12.5
14
14
  Requires-Dist: fastapi[standard]>=0.123.10 ; extra == 'webhook'
15
15
  Requires-Dist: ngrok>=1.4.0 ; extra == 'webhook'
16
16
  Requires-Dist: python-dotenv>=1.2.1 ; extra == 'webhook'
17
- Requires-Dist: typer-slim[standard]>=0.20.0 ; extra == 'webhook'
18
17
  Requires-Python: >=3.11
19
18
  Provides-Extra: webhook
20
19
  Description-Content-Type: text/markdown
@@ -47,7 +46,7 @@ $ uv add pypaystack2
47
46
  # For webhook cli
48
47
  $ pip install -U "pypaystack2[webhook]"
49
48
  or install with uv
50
- $ uv add "pypaystack2[webhook"
49
+ $ uv add "pypaystack2[webhook]"
51
50
  ```
52
51
 
53
52
  ## Usage Preview
@@ -26,7 +26,7 @@ $ uv add pypaystack2
26
26
  # For webhook cli
27
27
  $ pip install -U "pypaystack2[webhook]"
28
28
  or install with uv
29
- $ uv add "pypaystack2[webhook"
29
+ $ uv add "pypaystack2[webhook]"
30
30
  ```
31
31
 
32
32
  ## Usage Preview
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pypaystack2"
3
- version = "3.1.0"
3
+ version = "3.2.1"
4
4
  description = "A developer-friendly client library for Paystack"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -29,7 +29,6 @@ webhook = [
29
29
  "fastapi[standard]>=0.123.10",
30
30
  "ngrok>=1.4.0",
31
31
  "python-dotenv>=1.2.1",
32
- "typer-slim[standard]>=0.20.0",
33
32
  ]
34
33
 
35
34
  [build-system]
@@ -49,7 +48,6 @@ format = [
49
48
  test = [
50
49
  "python-dotenv>=1.2.1",
51
50
  "tomli>=2.3.0",
52
- "typer-slim[standard]>=0.20.0",
53
51
  ]
54
52
  coverage = []
55
53
  doc = [
@@ -1,5 +1,5 @@
1
1
  __title__ = "pypaystack2"
2
- __version__ = "3.1.0"
2
+ __version__ = "3.2.1"
3
3
  __author__ = [{"name": "Gbenga Adeyi", "email": "adeyigbenga005@gmail.com"}]
4
4
  __license__ = "MIT"
5
- __copyright__ = "Copyright 2025."
5
+ __copyright__ = "Copyright 2026."
@@ -11,7 +11,7 @@ from json import JSONDecodeError
11
11
  from typing import Any, Type, cast
12
12
 
13
13
  import httpx
14
- from httpx import NetworkError
14
+ from httpx import HTTPError
15
15
  from pydantic import ValidationError
16
16
 
17
17
  from pypaystack2._metadata import __version__
@@ -287,7 +287,7 @@ class BaseAPIClient(AbstractAPIClient):
287
287
 
288
288
  try:
289
289
  response = http_method_handler(**request_kwargs) # type: ignore
290
- except NetworkError as error:
290
+ except HTTPError as error:
291
291
  raise ClientNetworkError(f"network error occurred: {error}", error)
292
292
  return self._deserialize_response(
293
293
  response, response_data_model_class, raise_serialization_exception
@@ -327,7 +327,7 @@ class BaseAsyncAPIClient(AbstractAPIClient):
327
327
  raise ValueError("HTTP Request method not recognised or implemented")
328
328
  try:
329
329
  response = await http_method_handler(**request_kwargs)
330
- except NetworkError as error:
330
+ except HTTPError as error:
331
331
  raise ClientNetworkError(f"network error occurred: {error}", error)
332
332
 
333
333
  return self._deserialize_response(
@@ -44,10 +44,13 @@ class Channel(StrEnum):
44
44
 
45
45
  CARD = "card"
46
46
  BANK = "bank"
47
+ APPLE_PAY = "apple_pay"
47
48
  USSD = "ussd"
48
49
  QR = "qr"
49
50
  MOBILE_MONEY = "mobile_money"
50
51
  BANK_TRANSFER = "bank_transfer"
52
+ EFT = "eft"
53
+ PAYATTITUDE = "payattitude"
51
54
 
52
55
 
53
56
  class Bearer(StrEnum):
@@ -1,3 +1,9 @@
1
+ from pypaystack2.sub_clients.async_clients.direct_debits import AsyncDirectDebitClient
2
+ from pypaystack2.sub_clients.sync_clients.direct_debits import DirectDebitClient
3
+ from pypaystack2.sub_clients.async_clients.virtual_terminals import (
4
+ AsyncVirtualTerminalClient,
5
+ )
6
+ from pypaystack2.sub_clients.sync_clients.virtual_terminals import VirtualTerminalClient
1
7
  from pypaystack2.base_clients import BaseAPIClient, BaseAsyncAPIClient
2
8
  from pypaystack2.sub_clients import (
3
9
  ApplePayClient,
@@ -102,6 +108,10 @@ class PaystackClient(BaseAPIClient):
102
108
  Transfers control API e.g. `PaystackClient.transfer_control.check_balance`.
103
109
  verification: A binding to `VerificationClient` providing methods for interacting Paystack's Verification API
104
110
  e.g. `PaystackClient.verification.resolve_account_number`.
111
+ virtual_terminals: A binding to `VirtualTerminalClient` providing methods for interacting with Paystack's
112
+ Virtual Terminal API e.g. `VirtualTerminalClient.list`.
113
+ direct_debits: A binding to `DirectDebitClient` providing methods for interacting with Paystack's
114
+ Direct Debit API e.g. `DirectDebitClient.trigger_activation_charge`.
105
115
  """
106
116
 
107
117
  def __init__(self, secret_key: str | None = None):
@@ -157,6 +167,8 @@ class PaystackClient(BaseAPIClient):
157
167
  self.verification: VerificationClient = VerificationClient(
158
168
  secret_key=self._secret_key
159
169
  )
170
+ self.virtual_terminals = VirtualTerminalClient(secret_key=self._secret_key)
171
+ self.direct_debits = DirectDebitClient(secret_key=self._secret_key)
160
172
 
161
173
 
162
174
  class AsyncPaystackClient(BaseAsyncAPIClient):
@@ -167,51 +179,56 @@ class AsyncPaystackClient(BaseAsyncAPIClient):
167
179
 
168
180
  Attributes:
169
181
  apple_pay: A binding to `AsyncApplePayClient` providing methods for interacting Paystack's Apple Pay API
170
- e.g. `PaystackClient.apple_pay.get_domains`.
182
+ e.g. `AsyncPaystackClient.apple_pay.get_domains`.
171
183
  bulk_charges: A binding to `AsyncBulkChargeClient` providing methods for interacting Paystack's Bulk charge API
172
- e.g. `PaystackClient.bulk_charges.initiate`.
184
+ e.g. `AsyncPaystackClient.bulk_charges.initiate`.
173
185
  charge: A binding to `AsyncChargeClient` providing methods for interacting Paystack's Charge API
174
- e.g. `PaystackClient.charge.charge`.
186
+ e.g. `AsyncPaystackClient.charge.charge`.
175
187
  integration: A binding to `AsyncIntegrationClient` providing methods for interacting Paystack's Integration API
176
- e.g. `PaystackClient.integration.get_payment_session_timeout`.
188
+ e.g. `AsyncPaystackClient.integration.get_payment_session_timeout`.
177
189
  customers: A binding to `AsyncCustomerClient` providing methods for interacting Paystack's Customer API
178
- e.g. `PaystackClient.customers.create`.
190
+ e.g. `AsyncPaystackClient.customers.create`.
179
191
  dedicated_accounts: A binding to `AsyncDedicatedAccountClient` providing methods for interacting
180
192
  Paystack's Dedicated account API e.g. `PaystackClient.dedicated_accounts.create`.
181
193
  disputes: A binding to `AsyncDisputeClient` providing methods for interacting Paystack's Dispute API
182
- e.g. `PaystackClient.disputes.`.
194
+ e.g. `AsyncPaystackClient.disputes.`.
183
195
  payment_requests: A binding to `AsyncPaymentRequestClient` providing methods for interacting Paystack's Payment
184
- request API e.g. `PaystackClient.payment_requests.create`.
196
+ request API e.g. `AsyncPaystackClient.payment_requests.create`.
185
197
  miscellaneous: A binding to `AsyncApplePayClient` providing methods for interacting Paystack's Apple Pay API
186
- e.g. `PaystackClient.miscellaneous.get_banks`.
198
+ e.g. `AsyncPaystackClient.miscellaneous.get_banks`.
187
199
  payment_pages: A binding to `AsyncPaymentPageClient` providing methods for interacting Paystack's Payment Page
188
200
  API e.g. `PaystackClient.payment_pages.create`.
189
201
  plans: A binding to `AsyncPlanClient` providing methods for interacting Paystack's Plan API
190
- e.g. `PaystackClient.plans.get_plans`.
202
+ e.g. `AsyncPaystackClient.plans.get_plans`.
191
203
  products: A binding to `AsyncProductClient` providing methods for interacting Paystack's Product API
192
204
  e.g. `PaystackClient.products.get_product`.
193
205
  refunds: A binding to `AsyncRefundClient` providing methods for interacting Paystack's Refund API
194
- e.g. `PaystackClient.refunds.create`.
206
+ e.g. `AsyncPaystackClient.refunds.create`.
195
207
  settlements: A binding to `AsyncSettlementClient` providing methods for interacting Paystack's Settlement API
196
- e.g. `PaystackClient.settlements.get_settlements`.
208
+ e.g. `AsyncPaystackClient.settlements.get_settlements`.
197
209
  splits: A binding to `AsyncTransactionSplitClient` providing methods for interacting Paystack's Transaction
198
- split API e.g. `PaystackClient.splits.create`.
210
+ split API e.g. `AsyncPaystackClient.splits.create`.
199
211
  subaccounts: A binding to `AsyncSubAccountClient` providing methods for interacting Paystack's subaccount API
200
- e.g. `PaystackClient.subaccounts.create`.
212
+ e.g. `AsyncPaystackClient.subaccounts.create`.
201
213
  subscriptions: A binding to `AsyncSubscriptionClient` providing methods for interacting Paystack's Subscription
202
- API e.g. `PaystackClient.subscriptions.create`.
214
+ API e.g. `AsyncPaystackClient.subscriptions.create`.
203
215
  terminals: A binding to `AsyncTerminalClient` providing methods for interacting Paystack's Terminal API
204
- e.g. `PaystackClient.terminals.send_event`.
216
+ e.g. `AsyncPaystackClient.terminals.send_event`.
205
217
  transactions: A binding to `AsyncTransactionClient` providing methods for interacting Paystack's Transaction
206
- API e.g. `PaystackClient.transactions.initiate`.
218
+ API e.g. `AsyncPaystackClient.transactions.initiate`.
207
219
  transfer_recipients: A binding to `AsyncTransferRecipientClient` providing methods for interacting Paystack's
208
- Transfer recipients API e.g. `PaystackClient.transfer_recipients.create`.
220
+ Transfer recipients API e.g. `AsyncPaystackClient.transfer_recipients.create`.
209
221
  transfers: A binding to `AsyncTransferClient` providing methods for interacting Paystack's Transfer API
210
222
  e.g. `PaystackClient.transfers.finalize`.
211
223
  transfer_control: A binding to `AsyncTransferControlClient` providing methods for interacting Paystack's
212
- Transfers control API e.g. `PaystackClient.transfer_control.check_balance`.
224
+ Transfers control API e.g. `AsyncPaystackClient.transfer_control.check_balance`.
213
225
  verification: A binding to `AsyncVerificationClient` providing methods for interacting Paystack's Verification
214
- API e.g. `PaystackClient.verification.resolve_account_number`.
226
+ API e.g. `AsyncPaystackClient.verification.resolve_account_number`.
227
+ virtual_terminals: A binding to `VirtualTerminalClient` providing methods for interacting with Paystack's
228
+ Virtual Terminal API e.g. `AsyncVirtualTerminalClient.list`.
229
+ direct_debits: A binding to `AsyncDirectDebitClient` providing methods for interacting with Paystack's
230
+ Direct Debit API e.g. `AsyncDirectDebitClient.trigger_activation_charge`.
231
+
215
232
  """
216
233
 
217
234
  def __init__(self, secret_key: str | None = None):
@@ -243,3 +260,5 @@ class AsyncPaystackClient(BaseAsyncAPIClient):
243
260
  self.transfers = AsyncTransferClient(secret_key=self._secret_key)
244
261
  self.transfer_control = AsyncTransferControlClient(secret_key=self._secret_key)
245
262
  self.verification = AsyncVerificationClient(secret_key=self._secret_key)
263
+ self.virtual_terminals = AsyncVirtualTerminalClient(secret_key=self._secret_key)
264
+ self.direct_debits = AsyncDirectDebitClient(secret_key=self._secret_key)
@@ -1,5 +1,6 @@
1
1
  # ruff: noqa: F401
2
2
  from pypaystack2.models.payload_models import (
3
+ RefundAccount,
3
4
  BulkChargeInstruction,
4
5
  LineItem,
5
6
  Tax,
@@ -5,6 +5,22 @@ from pydantic import BaseModel, model_validator
5
5
  from pypaystack2.enums import RecipientType, Currency
6
6
 
7
7
 
8
+ class RefundAccount(BaseModel):
9
+ """A dataclass for representing refund account
10
+ details
11
+
12
+ Attributes:
13
+ currency:The currency of the customer's bank account.
14
+ It should be the same as the currency the payment was made
15
+ account_number: The customer's account number
16
+ bank_id: The ID representing the customer's bank.
17
+ """
18
+
19
+ currency: Currency
20
+ account_number: str
21
+ bank_id: str
22
+
23
+
8
24
  class BulkChargeInstruction(BaseModel):
9
25
  """A dataclass for bulk charge instruction.
10
26
 
@@ -1,5 +1,5 @@
1
1
  from http import HTTPMethod
2
- from typing import Any
2
+ from typing import Any, Literal
3
3
 
4
4
  from pypaystack2.base_clients import BaseAsyncAPIClient, add_to_payload
5
5
  from pypaystack2.models import Response
@@ -19,14 +19,19 @@ class AsyncChargeClient(BaseAsyncAPIClient):
19
19
  self,
20
20
  email: str,
21
21
  amount: int,
22
+ split_code: str | None = None,
23
+ subaccount: str | None = None,
24
+ transaction_charge: str | None = None,
25
+ bearer: Literal["account", "subaccount"] | None = "account",
22
26
  bank: dict[str, Any] | None = None,
23
27
  bank_transfer: dict[str, Any] | None = None,
28
+ ussd: dict[str, Any] | None = None,
29
+ mobile_money: dict[str, Any] | None = None,
30
+ qr: dict[str, Any] | None = None,
24
31
  auth_code: str | None = None,
25
32
  pin: str | None = None,
26
33
  metadata: dict[str, Any] | None = None,
27
34
  reference: str | None = None,
28
- ussd: dict[str, Any] | None = None,
29
- mobile_money: dict[str, Any] | None = None,
30
35
  device_id: str | None = None,
31
36
  alternate_model_class: type[PaystackDataModel] | None = None,
32
37
  ) -> Response[ChargeStep] | Response[PaystackDataModel]:
@@ -36,15 +41,21 @@ class AsyncChargeClient(BaseAsyncAPIClient):
36
41
  email: Customer's email address
37
42
  amount: Amount should be in kobo if currency is NGN, pesewas, if currency is GHS,
38
43
  and cents, if currency is ZAR
44
+ split_code: The split code of a previously created split. e.g. `SPL_98WF13Eb3w`
45
+ subaccount: The code for the subaccount that owns the payment. e.g. `ACCT_8f4s1eq7ml6rlzj`
46
+ transaction_charge: An amount used to override the split configuration for a single split payment.
47
+ If set, the amount specified goes to the main account regardless of the split configuration.
48
+ bearer: Use this param to indicate who bears the transaction charges.
39
49
  bank: Bank account to charge (don't send if charging an authorization code)
40
50
  bank_transfer: Takes the settings for the Pay with Transfer (PwT) channel. Pass in the
41
51
  account_expires_at param to set the expiry time.
52
+ ussd: USSD type to charge (don't send if charging an authorization code, bank or card)
53
+ mobile_money: Mobile details (don't send if charging an authorization code, bank or card)
54
+ qr: Takes a provider parameter with the value set to: scan-to-pay. Currently supported in South Africa only.
42
55
  auth_code: An authorization code to charge (don't send if charging a bank account)
43
56
  pin: 4-digit PIN (send with a non-reusable authorization code)
44
57
  metadata: A dictionary of data.
45
58
  reference: Unique transaction reference. Only -, .\\`, = and alphanumeric characters allowed.
46
- ussd: USSD type to charge (don't send if charging an authorization code, bank or card)
47
- mobile_money: Mobile details (don't send if charging an authorization code, bank or card)
48
59
  device_id: This is the unique identifier of the device a user uses in making payment. Only -, .\\`,
49
60
  = and alphanumeric characters allowed.
50
61
  alternate_model_class: A pydantic model class to use instead of the
@@ -66,14 +77,19 @@ class AsyncChargeClient(BaseAsyncAPIClient):
66
77
 
67
78
  payload = {"email": email, "amount": amount}
68
79
  optional_params = [
80
+ ("split_code", split_code),
81
+ ("subaccount", subaccount),
82
+ ("transaction_charge", transaction_charge),
83
+ ("bearer", bearer),
69
84
  ("bank", bank),
70
85
  ("bank_transfer", bank_transfer),
86
+ ("ussd", ussd),
87
+ ("mobile_money", mobile_money),
88
+ ("qr", qr),
71
89
  ("authorization_code", auth_code),
72
90
  ("pin", pin),
73
91
  ("metadata", metadata),
74
92
  ("reference", reference),
75
- ("ussd", ussd),
76
- ("mobile_money", mobile_money),
77
93
  ("device_id", device_id),
78
94
  ]
79
95
  payload = add_to_payload(optional_params, payload)
@@ -329,6 +329,198 @@ class AsyncCustomerClient(BaseAsyncAPIClient):
329
329
  response_data_model_class=alternate_model_class or Customer,
330
330
  )
331
331
 
332
+ async def initialize_authorization(
333
+ self,
334
+ email: str,
335
+ callback_url: str | None = None,
336
+ account: dict[str, Any] | None = None,
337
+ address: dict[str, Any] | None = None,
338
+ channel: str = "direct-debit",
339
+ alternate_model_class: type[PaystackDataModel] | None = None,
340
+ ):
341
+ """Initiate a request to create a reusable authorization code for recurring transactions.
342
+
343
+ Args:
344
+ alternate_model_class: A pydantic model class to use instead of the
345
+ default pydantic model used by the library to present the data in
346
+ the `Response.data`. The default behaviour of the library is to
347
+ set `Response.data` to `None` if it fails to serialize the data
348
+ returned from paystack with the model provided in the library.
349
+ Providing a pydantic model class via this parameter overrides
350
+ the library default model with the model class you provide.
351
+ This can come in handy when the models in the library do not
352
+ accurately represent the data returned, and you prefer working with the
353
+ data as a pydantic model instead of as a dict of the response returned
354
+ by paystack before it is serialized with pydantic models, The original
355
+ data can be accessed via `Response.raw`.
356
+
357
+ Returns:
358
+ A pydantic model containing the response gotten from paystack's server.
359
+ """
360
+ url = self._full_url("/customer/authorization/initialize")
361
+ payload = {
362
+ "email": email,
363
+ "channel": channel,
364
+ }
365
+ optional_params = [
366
+ ("callback_url", callback_url),
367
+ ("account", account),
368
+ ("address", address),
369
+ ]
370
+ payload = add_to_payload(optional_params, payload)
371
+ return await self._handle_request(
372
+ HTTPMethod.POST,
373
+ url,
374
+ payload,
375
+ response_data_model_class=alternate_model_class,
376
+ )
377
+
378
+ async def verify_authorization(
379
+ self,
380
+ reference: str,
381
+ alternate_model_class: type[PaystackDataModel] | None = None,
382
+ ):
383
+ """Check the status of an authorization request.
384
+
385
+ Args:
386
+ reference: The reference returned in the initialization response
387
+ alternate_model_class: A pydantic model class to use instead of the
388
+ default pydantic model used by the library to present the data in
389
+ the `Response.data`. The default behaviour of the library is to
390
+ set `Response.data` to `None` if it fails to serialize the data
391
+ returned from paystack with the model provided in the library.
392
+ Providing a pydantic model class via this parameter overrides
393
+ the library default model with the model class you provide.
394
+ This can come in handy when the models in the library do not
395
+ accurately represent the data returned, and you prefer working with the
396
+ data as a pydantic model instead of as a dict of the response returned
397
+ by paystack before it is serialized with pydantic models, The original
398
+ data can be accessed via `Response.raw`.
399
+
400
+ Returns:
401
+ A pydantic model containing the response gotten from paystack's server.
402
+ """
403
+ url = self._full_url(f"/customer/authorization/verify/{reference}")
404
+ return await self._handle_request(
405
+ HTTPMethod.GET,
406
+ url,
407
+ response_data_model_class=alternate_model_class,
408
+ )
409
+
410
+ async def initialize_direct_debit(
411
+ self,
412
+ customer_id: str | int,
413
+ account: dict[str, Any],
414
+ address: dict[str, Any],
415
+ alternate_model_class: type[PaystackDataModel] | None = None,
416
+ ):
417
+ """Initialize the process of linking an account to a customer for Direct Debit transactions.
418
+
419
+ Args:
420
+ customer_id: The id of the customer.
421
+ account: the customer's acount details. it should have a key `number`
422
+ with a value that is the customer's account number, a key `bank_code`
423
+ that is the code representing the customer's bank.
424
+ address: the customer's address information. it should have the keys
425
+ `street`, `city` and `state` that is the customer's address information
426
+ alternate_model_class: A pydantic model class to use instead of the
427
+ default pydantic model used by the library to present the data in
428
+ the `Response.data`. The default behaviour of the library is to
429
+ set `Response.data` to `None` if it fails to serialize the data
430
+ returned from paystack with the model provided in the library.
431
+ Providing a pydantic model class via this parameter overrides
432
+ the library default model with the model class you provide.
433
+ This can come in handy when the models in the library do not
434
+ accurately represent the data returned, and you prefer working with the
435
+ data as a pydantic model instead of as a dict of the response returned
436
+ by paystack before it is serialized with pydantic models, The original
437
+ data can be accessed via `Response.raw`.
438
+
439
+ Returns:
440
+ A pydantic model containing the response gotten from paystack's server.
441
+ """
442
+ url = self._full_url(f"/customer/{customer_id}/initialize-direct-debit")
443
+ payload = {
444
+ "account": account,
445
+ "address": address,
446
+ }
447
+ return await self._handle_request(
448
+ HTTPMethod.POST,
449
+ url,
450
+ payload,
451
+ response_data_model_class=alternate_model_class,
452
+ )
453
+
454
+ async def trigger_activation_charge(
455
+ self,
456
+ customer_id: str | int,
457
+ authorization_id: str | int,
458
+ alternate_model_class: type[PaystackDataModel] | None = None,
459
+ ):
460
+ """Trigger an activation charge on an inactive mandate on behalf of your customer.
461
+
462
+ Args:
463
+ customer_id: The customer ID attacted to the authorization
464
+ authorization_id: The authorization ID gotten from the initiation response
465
+ alternate_model_class: A pydantic model class to use instead of the
466
+ default pydantic model used by the library to present the data in
467
+ the `Response.data`. The default behaviour of the library is to
468
+ set `Response.data` to `None` if it fails to serialize the data
469
+ returned from paystack with the model provided in the library.
470
+ Providing a pydantic model class via this parameter overrides
471
+ the library default model with the model class you provide.
472
+ This can come in handy when the models in the library do not
473
+ accurately represent the data returned, and you prefer working with the
474
+ data as a pydantic model instead of as a dict of the response returned
475
+ by paystack before it is serialized with pydantic models, The original
476
+ data can be accessed via `Response.raw`.
477
+
478
+ Returns:
479
+ A pydantic model containing the response gotten from paystack's server.
480
+ """
481
+ url = self._full_url(f"/customer/{customer_id}/directdebit-activation-charge")
482
+ payload = {
483
+ "authorization_id": authorization_id,
484
+ }
485
+ return await self._handle_request(
486
+ HTTPMethod.PUT,
487
+ url,
488
+ payload,
489
+ response_data_model_class=alternate_model_class,
490
+ )
491
+
492
+ async def get_mandate_authorizations(
493
+ self,
494
+ id_: str | int,
495
+ alternate_model_class: type[PaystackDataModel] | None = None,
496
+ ):
497
+ """Get the list of direct debit mandates associated with a customer.
498
+
499
+ Args:
500
+ id_: The customer ID for the authorizations to fetch
501
+ alternate_model_class: A pydantic model class to use instead of the
502
+ default pydantic model used by the library to present the data in
503
+ the `Response.data`. The default behaviour of the library is to
504
+ set `Response.data` to `None` if it fails to serialize the data
505
+ returned from paystack with the model provided in the library.
506
+ Providing a pydantic model class via this parameter overrides
507
+ the library default model with the model class you provide.
508
+ This can come in handy when the models in the library do not
509
+ accurately represent the data returned, and you prefer working with the
510
+ data as a pydantic model instead of as a dict of the response returned
511
+ by paystack before it is serialized with pydantic models, The original
512
+ data can be accessed via `Response.raw`.
513
+
514
+ Returns:
515
+ A pydantic model containing the response gotten from paystack's server.
516
+ """
517
+ url = self._full_url(f"/customer/{id_}/directdebit-mandate-authorizations")
518
+ return await self._handle_request(
519
+ HTTPMethod.GET,
520
+ url,
521
+ response_data_model_class=alternate_model_class,
522
+ )
523
+
332
524
  async def deactivate(
333
525
  self,
334
526
  auth_code: str,
@@ -355,7 +547,7 @@ class AsyncCustomerClient(BaseAsyncAPIClient):
355
547
  A pydantic model containing the response gotten from paystack's server.
356
548
  """
357
549
 
358
- url = self._full_url("/customer/deactivate_authorization")
550
+ url = self._full_url("/customer/authorization/deactivate")
359
551
  payload = {
360
552
  "authorization_code": auth_code,
361
553
  }
@@ -0,0 +1,91 @@
1
+ from typing import Literal
2
+ from http import HTTPMethod
3
+ from pypaystack2.types import PaystackDataModel
4
+ from pypaystack2.base_clients import BaseAsyncAPIClient, append_query_params
5
+
6
+
7
+ class AsyncDirectDebitClient(BaseAsyncAPIClient):
8
+ """This client provides API for interacting with Paystack's Direct Debit API
9
+
10
+ The Direct Debit API allows you manage the authorization on your customer's bank accounts.
11
+ """
12
+
13
+ async def trigger_activation_charge(
14
+ self,
15
+ customer_ids: list[str | int],
16
+ alternate_model_class: type[PaystackDataModel] | None = None,
17
+ ):
18
+ """Trigger an activation charge on an inactive mandate on behalf of your customer.
19
+
20
+ Args:
21
+ customer_ids: A list of customer IDs with pending mandate authorizations.
22
+ alternate_model_class: A pydantic model class to use instead of the
23
+ default pydantic model used by the library to present the data in
24
+ the `Response.data`. The default behaviour of the library is to
25
+ set `Response.data` to `None` if it fails to serialize the data
26
+ returned from paystack with the model provided in the library.
27
+ Providing a pydantic model class via this parameter overrides
28
+ the library default model with the model class you provide.
29
+ This can come in handy when the models in the library do not
30
+ accurately represent the data returned, and you prefer working with the
31
+ data as a pydantic model instead of as a dict of the response returned
32
+ by paystack before it is serialized with pydantic models, The original
33
+ data can be accessed via `Response.raw`.
34
+
35
+ Returns:
36
+ A pydantic model containing the response gotten from paystack's server.
37
+ """
38
+ url = self._full_url("/directdebit/activation-charge")
39
+ payload = {
40
+ "customer_ids": customer_ids,
41
+ }
42
+ return await self._handle_request(
43
+ HTTPMethod.PUT,
44
+ url,
45
+ payload,
46
+ response_data_model_class=alternate_model_class,
47
+ )
48
+
49
+ async def get_mandate_authorizations(
50
+ self,
51
+ cursor: str | None = None,
52
+ status: Literal["pending", "active", "revoked"] | None = None,
53
+ pagination: int = 50,
54
+ alternate_model_class: type[PaystackDataModel] | None = None,
55
+ ):
56
+ """Get the list of direct debit mandates associated with a customer.
57
+
58
+ Args:
59
+ cursor: The cursor value of the next set of authorizations to fetch.
60
+ You can get this from the meta object of the response
61
+ status: Filter by the authorization status.
62
+ pagination: The number of authorizations to fetch per call
63
+ alternate_model_class: A pydantic model class to use instead of the
64
+ default pydantic model used by the library to present the data in
65
+ the `Response.data`. The default behaviour of the library is to
66
+ set `Response.data` to `None` if it fails to serialize the data
67
+ returned from paystack with the model provided in the library.
68
+ Providing a pydantic model class via this parameter overrides
69
+ the library default model with the model class you provide.
70
+ This can come in handy when the models in the library do not
71
+ accurately represent the data returned, and you prefer working with the
72
+ data as a pydantic model instead of as a dict of the response returned
73
+ by paystack before it is serialized with pydantic models, The original
74
+ data can be accessed via `Response.raw`.
75
+
76
+ Returns:
77
+ A pydantic model containing the response gotten from paystack's server.
78
+ """
79
+ query_params = [
80
+ ("cursor", cursor),
81
+ ("status", status),
82
+ ]
83
+ url = self._full_url(
84
+ f"/directdebit/mandate-authorizations?per_page={pagination}"
85
+ )
86
+ url = append_query_params(query_params, url)
87
+ return await self._handle_request(
88
+ HTTPMethod.GET,
89
+ url,
90
+ response_data_model_class=alternate_model_class,
91
+ )
@@ -26,6 +26,7 @@ class AsyncMiscellaneousClient(BaseAsyncAPIClient):
26
26
  pay_with_bank_transfer: bool | None = None,
27
27
  pay_with_bank: bool | None = None,
28
28
  include_nip_sort_code: bool | None = None,
29
+ enabled_for_verificaton: bool | None = None,
29
30
  pagination: int = 50,
30
31
  alternate_model_class: type[PaystackDataModel] | None = None,
31
32
  ) -> Response[list[Bank]] | Response[PaystackDataModel]:
@@ -44,6 +45,8 @@ class AsyncMiscellaneousClient(BaseAsyncAPIClient):
44
45
  pay_with_bank_transfer: A flag to filter for available banks a customer can make a transfer to
45
46
  complete a payment
46
47
  pay_with_bank: A flag to filter for banks a customer can pay directly from
48
+ enabled_for_verificaton: A flag to filter the banks that are supported for account verification in South Africa.
49
+ You need to combine this with either the currency or country filter.
47
50
  pagination: The number of objects to return per page. Defaults to 50, and limited to 100 records per page.
48
51
  alternate_model_class: A pydantic model class to use instead of the
49
52
  default pydantic model used by the library to present the data in
@@ -77,6 +80,7 @@ class AsyncMiscellaneousClient(BaseAsyncAPIClient):
77
80
  ("pay_with_bank_transfer", pay_with_bank_transfer),
78
81
  ("pay_with_bank", pay_with_bank),
79
82
  ("include_nip_sort_code", include_nip_sort_code),
83
+ ("enabled_for_verificaton", enabled_for_verificaton),
80
84
  ]
81
85
  url = append_query_params(query_params, url)
82
86
  return await self._handle_request( # type: ignore