finswitz 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.
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.4
2
+ Name: finswitz
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for the Finswitz API
5
+ Author: Finswitz
6
+ License: MIT
7
+ Keywords: payments,fintech,finswitz,api
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+
14
+ # Finswitz Python SDK
15
+
16
+ Python client for the Finswitz API.
17
+
18
+ ## Installation
19
+
20
+ The Python SDK is currently distributed as a source client. Add `finswitz.py` to your application package, then import `Finswitz`.
21
+
22
+ When a package is published, this README should be updated with the package manager install command.
23
+
24
+ ## Requirements
25
+
26
+ - Python 3.9 or newer
27
+ - A Finswitz test or live secret key
28
+
29
+ ## Quick Start
30
+
31
+ ```python
32
+ import os
33
+ from finswitz import Finswitz
34
+
35
+ client = Finswitz(api_key=os.environ["FINSWITZ_SECRET_KEY"])
36
+
37
+ link = client.create_payment_link(
38
+ {
39
+ "amount": 5000,
40
+ "currency": "NGN",
41
+ "title": "Order #1234",
42
+ "email": "buyer@example.com",
43
+ "callback_url": "https://merchant.example/complete",
44
+ },
45
+ idempotency_key="order-1234-link",
46
+ )
47
+
48
+ print(link["checkoutUrl"])
49
+ ```
50
+
51
+ ## Custom Base URL
52
+
53
+ ```python
54
+ client = Finswitz(
55
+ api_key=os.environ["FINSWITZ_SECRET_KEY"],
56
+ base_url="http://localhost:4000",
57
+ )
58
+ ```
59
+
60
+ ## Payments
61
+
62
+ ```python
63
+ client.transfer(
64
+ {
65
+ "amount": 5000,
66
+ "currency": "NGN",
67
+ "bank_code": "058",
68
+ "account_number": "0123456789",
69
+ "narration": "Vendor payout",
70
+ },
71
+ idempotency_key="transfer-001",
72
+ )
73
+
74
+ client.mobile_money(
75
+ {
76
+ "amount": 1500,
77
+ "currency": "GHS",
78
+ "phone": "+233501112222",
79
+ "country": "GH",
80
+ },
81
+ idempotency_key="momo-001",
82
+ )
83
+
84
+ transaction = client.get_transaction("reference")
85
+ ```
86
+
87
+ ## Dashboard JWT Helpers
88
+
89
+ ```python
90
+ client = Finswitz(
91
+ api_key=os.environ["FINSWITZ_SECRET_KEY"],
92
+ dashboard_token=os.environ["FINSWITZ_DASHBOARD_TOKEN"],
93
+ )
94
+
95
+ client.update_webhooks(
96
+ {
97
+ "mode": "test",
98
+ "url": "https://merchant.example/webhooks/finswitz",
99
+ }
100
+ )
101
+
102
+ wallets = client.wallets()
103
+ treasury = client.treasury()
104
+ ```
105
+
106
+ ## Collections
107
+
108
+ ```python
109
+ collection = client.public_collection("school-fees")
110
+
111
+ payment = client.pay_collection(
112
+ "school-fees",
113
+ {
114
+ "fullName": "Grace Johnson",
115
+ "email": "grace@example.com",
116
+ "amount": 10000,
117
+ "phone": "+2348012345678",
118
+ },
119
+ )
120
+ ```
121
+
122
+ ## Error Handling
123
+
124
+ ```python
125
+ from finswitz import FinswitzApiError
126
+
127
+ try:
128
+ client.get_transaction("missing-reference")
129
+ except FinswitzApiError as error:
130
+ print(error.status)
131
+ print(error.response)
132
+ raise
133
+ ```
134
+
@@ -0,0 +1,121 @@
1
+ # Finswitz Python SDK
2
+
3
+ Python client for the Finswitz API.
4
+
5
+ ## Installation
6
+
7
+ The Python SDK is currently distributed as a source client. Add `finswitz.py` to your application package, then import `Finswitz`.
8
+
9
+ When a package is published, this README should be updated with the package manager install command.
10
+
11
+ ## Requirements
12
+
13
+ - Python 3.9 or newer
14
+ - A Finswitz test or live secret key
15
+
16
+ ## Quick Start
17
+
18
+ ```python
19
+ import os
20
+ from finswitz import Finswitz
21
+
22
+ client = Finswitz(api_key=os.environ["FINSWITZ_SECRET_KEY"])
23
+
24
+ link = client.create_payment_link(
25
+ {
26
+ "amount": 5000,
27
+ "currency": "NGN",
28
+ "title": "Order #1234",
29
+ "email": "buyer@example.com",
30
+ "callback_url": "https://merchant.example/complete",
31
+ },
32
+ idempotency_key="order-1234-link",
33
+ )
34
+
35
+ print(link["checkoutUrl"])
36
+ ```
37
+
38
+ ## Custom Base URL
39
+
40
+ ```python
41
+ client = Finswitz(
42
+ api_key=os.environ["FINSWITZ_SECRET_KEY"],
43
+ base_url="http://localhost:4000",
44
+ )
45
+ ```
46
+
47
+ ## Payments
48
+
49
+ ```python
50
+ client.transfer(
51
+ {
52
+ "amount": 5000,
53
+ "currency": "NGN",
54
+ "bank_code": "058",
55
+ "account_number": "0123456789",
56
+ "narration": "Vendor payout",
57
+ },
58
+ idempotency_key="transfer-001",
59
+ )
60
+
61
+ client.mobile_money(
62
+ {
63
+ "amount": 1500,
64
+ "currency": "GHS",
65
+ "phone": "+233501112222",
66
+ "country": "GH",
67
+ },
68
+ idempotency_key="momo-001",
69
+ )
70
+
71
+ transaction = client.get_transaction("reference")
72
+ ```
73
+
74
+ ## Dashboard JWT Helpers
75
+
76
+ ```python
77
+ client = Finswitz(
78
+ api_key=os.environ["FINSWITZ_SECRET_KEY"],
79
+ dashboard_token=os.environ["FINSWITZ_DASHBOARD_TOKEN"],
80
+ )
81
+
82
+ client.update_webhooks(
83
+ {
84
+ "mode": "test",
85
+ "url": "https://merchant.example/webhooks/finswitz",
86
+ }
87
+ )
88
+
89
+ wallets = client.wallets()
90
+ treasury = client.treasury()
91
+ ```
92
+
93
+ ## Collections
94
+
95
+ ```python
96
+ collection = client.public_collection("school-fees")
97
+
98
+ payment = client.pay_collection(
99
+ "school-fees",
100
+ {
101
+ "fullName": "Grace Johnson",
102
+ "email": "grace@example.com",
103
+ "amount": 10000,
104
+ "phone": "+2348012345678",
105
+ },
106
+ )
107
+ ```
108
+
109
+ ## Error Handling
110
+
111
+ ```python
112
+ from finswitz import FinswitzApiError
113
+
114
+ try:
115
+ client.get_transaction("missing-reference")
116
+ except FinswitzApiError as error:
117
+ print(error.status)
118
+ print(error.response)
119
+ raise
120
+ ```
121
+
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.4
2
+ Name: finswitz
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for the Finswitz API
5
+ Author: Finswitz
6
+ License: MIT
7
+ Keywords: payments,fintech,finswitz,api
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+
14
+ # Finswitz Python SDK
15
+
16
+ Python client for the Finswitz API.
17
+
18
+ ## Installation
19
+
20
+ The Python SDK is currently distributed as a source client. Add `finswitz.py` to your application package, then import `Finswitz`.
21
+
22
+ When a package is published, this README should be updated with the package manager install command.
23
+
24
+ ## Requirements
25
+
26
+ - Python 3.9 or newer
27
+ - A Finswitz test or live secret key
28
+
29
+ ## Quick Start
30
+
31
+ ```python
32
+ import os
33
+ from finswitz import Finswitz
34
+
35
+ client = Finswitz(api_key=os.environ["FINSWITZ_SECRET_KEY"])
36
+
37
+ link = client.create_payment_link(
38
+ {
39
+ "amount": 5000,
40
+ "currency": "NGN",
41
+ "title": "Order #1234",
42
+ "email": "buyer@example.com",
43
+ "callback_url": "https://merchant.example/complete",
44
+ },
45
+ idempotency_key="order-1234-link",
46
+ )
47
+
48
+ print(link["checkoutUrl"])
49
+ ```
50
+
51
+ ## Custom Base URL
52
+
53
+ ```python
54
+ client = Finswitz(
55
+ api_key=os.environ["FINSWITZ_SECRET_KEY"],
56
+ base_url="http://localhost:4000",
57
+ )
58
+ ```
59
+
60
+ ## Payments
61
+
62
+ ```python
63
+ client.transfer(
64
+ {
65
+ "amount": 5000,
66
+ "currency": "NGN",
67
+ "bank_code": "058",
68
+ "account_number": "0123456789",
69
+ "narration": "Vendor payout",
70
+ },
71
+ idempotency_key="transfer-001",
72
+ )
73
+
74
+ client.mobile_money(
75
+ {
76
+ "amount": 1500,
77
+ "currency": "GHS",
78
+ "phone": "+233501112222",
79
+ "country": "GH",
80
+ },
81
+ idempotency_key="momo-001",
82
+ )
83
+
84
+ transaction = client.get_transaction("reference")
85
+ ```
86
+
87
+ ## Dashboard JWT Helpers
88
+
89
+ ```python
90
+ client = Finswitz(
91
+ api_key=os.environ["FINSWITZ_SECRET_KEY"],
92
+ dashboard_token=os.environ["FINSWITZ_DASHBOARD_TOKEN"],
93
+ )
94
+
95
+ client.update_webhooks(
96
+ {
97
+ "mode": "test",
98
+ "url": "https://merchant.example/webhooks/finswitz",
99
+ }
100
+ )
101
+
102
+ wallets = client.wallets()
103
+ treasury = client.treasury()
104
+ ```
105
+
106
+ ## Collections
107
+
108
+ ```python
109
+ collection = client.public_collection("school-fees")
110
+
111
+ payment = client.pay_collection(
112
+ "school-fees",
113
+ {
114
+ "fullName": "Grace Johnson",
115
+ "email": "grace@example.com",
116
+ "amount": 10000,
117
+ "phone": "+2348012345678",
118
+ },
119
+ )
120
+ ```
121
+
122
+ ## Error Handling
123
+
124
+ ```python
125
+ from finswitz import FinswitzApiError
126
+
127
+ try:
128
+ client.get_transaction("missing-reference")
129
+ except FinswitzApiError as error:
130
+ print(error.status)
131
+ print(error.response)
132
+ raise
133
+ ```
134
+
@@ -0,0 +1,7 @@
1
+ README.md
2
+ finswitz.py
3
+ pyproject.toml
4
+ finswitz.egg-info/PKG-INFO
5
+ finswitz.egg-info/SOURCES.txt
6
+ finswitz.egg-info/dependency_links.txt
7
+ finswitz.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ finswitz
@@ -0,0 +1,200 @@
1
+ import json
2
+ from urllib.parse import urlencode
3
+ from urllib.request import Request, urlopen
4
+ from urllib.error import HTTPError
5
+
6
+
7
+ DEFAULT_BASE_URL = "https://api.finswitz.com"
8
+
9
+
10
+ class FinswitzApiError(Exception):
11
+ def __init__(self, message, status=None, response=None):
12
+ super().__init__(message)
13
+ self.status = status
14
+ self.response = response
15
+
16
+
17
+ class Finswitz:
18
+ def __init__(self, api_key=None, dashboard_token=None, base_url=DEFAULT_BASE_URL):
19
+ self.api_key = api_key
20
+ self.dashboard_token = dashboard_token
21
+ self.base_url = base_url.rstrip("/")
22
+
23
+ def request(self, method, path, body=None, query=None, idempotency_key=None, token_type="api", token=None):
24
+ bearer = token or (self.dashboard_token if token_type == "dashboard" else self.api_key)
25
+ if token_type != "none" and not bearer:
26
+ raise ValueError("Missing dashboard_token." if token_type == "dashboard" else "Missing api_key.")
27
+
28
+ url = self.base_url + path
29
+ if query:
30
+ clean_query = {key: value for key, value in query.items() if value is not None}
31
+ if clean_query:
32
+ url += "?" + urlencode(clean_query)
33
+
34
+ payload = None if body is None else json.dumps(body).encode("utf-8")
35
+ headers = {"Accept": "application/json"}
36
+ if token_type != "none":
37
+ headers["Authorization"] = "Bearer " + bearer
38
+ if body is not None:
39
+ headers["Content-Type"] = "application/json"
40
+ if idempotency_key:
41
+ headers["Idempotency-Key"] = idempotency_key
42
+
43
+ req = Request(url, data=payload, headers=headers, method=method)
44
+ try:
45
+ with urlopen(req, timeout=30) as res:
46
+ text = res.read().decode("utf-8")
47
+ return json.loads(text) if text else None
48
+ except HTTPError as err:
49
+ text = err.read().decode("utf-8")
50
+ data = json.loads(text) if text else None
51
+ message = data.get("error") if isinstance(data, dict) else None
52
+ raise FinswitzApiError(message or f"Finswitz API request failed with {err.code}", err.code, data)
53
+
54
+ def get(self, path, **kwargs):
55
+ return self.request("GET", path, **kwargs)
56
+
57
+ def post(self, path, body=None, **kwargs):
58
+ return self.request("POST", path, body=body or {}, **kwargs)
59
+
60
+ def patch(self, path, body=None, **kwargs):
61
+ return self.request("PATCH", path, body=body or {}, **kwargs)
62
+
63
+ def transfer(self, payload, idempotency_key=None):
64
+ return self.post("/payments/transfer", payload, idempotency_key=idempotency_key)
65
+
66
+ def verify_account(self, payload):
67
+ return self.post("/payments/verify-account", payload)
68
+
69
+ def create_payment_link(self, payload, idempotency_key=None):
70
+ return self.post("/payments/payment-links", payload, idempotency_key=idempotency_key)
71
+
72
+ def mobile_money(self, payload, idempotency_key=None):
73
+ return self.post("/payments/mobile-money", payload, idempotency_key=idempotency_key)
74
+
75
+ def mock_charge(self, payload):
76
+ return self.post("/payments/mock/charge", payload)
77
+
78
+ def get_transaction(self, reference):
79
+ return self.get(f"/payments/{reference}")
80
+
81
+ def list_transactions(self, query=None):
82
+ return self.get("/payments", query=query)
83
+
84
+ def refund(self, reference, payload=None, idempotency_key=None):
85
+ return self.post(f"/payments/{reference}/refund", payload or {}, idempotency_key=idempotency_key)
86
+
87
+ def list_banks(self, query=None):
88
+ return self.get("/payments/banks", query=query)
89
+
90
+ def card_pricing(self):
91
+ return self.get("/cards/pricing")
92
+
93
+ def issue_card(self, payload, idempotency_key=None):
94
+ return self.post("/cards/issue", payload, idempotency_key=idempotency_key)
95
+
96
+ def list_cards(self, query=None):
97
+ return self.get("/cards", query=query)
98
+
99
+ def list_card_transactions(self, card_id, query=None):
100
+ return self.get(f"/cards/{card_id}/transactions", query=query)
101
+
102
+ def get_card_transaction(self, card_id, transaction_id):
103
+ return self.get(f"/cards/{card_id}/transactions/{transaction_id}")
104
+
105
+ def me(self):
106
+ return self.get("/developers/me", token_type="dashboard")
107
+
108
+ def list_api_keys(self):
109
+ return self.get("/developers/keys", token_type="dashboard")
110
+
111
+ def create_api_key(self, payload):
112
+ return self.post("/developers/keys", payload, token_type="dashboard")
113
+
114
+ def revoke_api_key(self, key_id):
115
+ return self.post(f"/developers/keys/{key_id}/revoke", {}, token_type="dashboard")
116
+
117
+ def update_webhooks(self, payload):
118
+ return self.request("PUT", "/developers/webhooks", body=payload, token_type="dashboard")
119
+
120
+ def list_webhook_logs(self, query=None):
121
+ return self.get("/developers/webhooks/logs", query=query, token_type="dashboard")
122
+
123
+ def simulate_webhook(self, payload):
124
+ return self.post("/developers/webhooks/simulate", payload, token_type="dashboard")
125
+
126
+ def wallets(self):
127
+ return self.get("/developers/wallets", token_type="dashboard")
128
+
129
+ def fund_wallet(self, payload):
130
+ return self.post("/developers/wallets/fund", payload, token_type="dashboard")
131
+
132
+ def wallet_funding_status(self, query=None):
133
+ return self.get("/developers/wallets/fund/status", query=query, token_type="dashboard")
134
+
135
+ def convert_wallet(self, payload):
136
+ return self.post("/developers/wallets/convert", payload, token_type="dashboard")
137
+
138
+ def treasury(self):
139
+ return self.get("/developers/treasury", token_type="dashboard")
140
+
141
+ def list_split_rules(self):
142
+ return self.get("/developers/treasury/split-rules", token_type="dashboard")
143
+
144
+ def create_split_rule(self, payload, idempotency_key=None):
145
+ return self.post("/developers/treasury/split-rules", payload, idempotency_key=idempotency_key, token_type="dashboard")
146
+
147
+ def update_split_rule(self, rule_id, payload):
148
+ return self.patch(f"/developers/treasury/split-rules/{rule_id}", payload, token_type="dashboard")
149
+
150
+ def list_escrow_holds(self):
151
+ return self.get("/developers/treasury/escrow", token_type="dashboard")
152
+
153
+ def create_escrow_hold(self, payload, idempotency_key=None):
154
+ return self.post("/developers/treasury/escrow", payload, idempotency_key=idempotency_key, token_type="dashboard")
155
+
156
+ def release_escrow_hold(self, hold_id, payload=None, idempotency_key=None):
157
+ return self.post(f"/developers/treasury/escrow/{hold_id}/release", payload or {}, idempotency_key=idempotency_key, token_type="dashboard")
158
+
159
+ def list_vendor_settlements(self):
160
+ return self.get("/developers/treasury/settlements", token_type="dashboard")
161
+
162
+ def execute_vendor_settlement(self, settlement_id, payload=None, idempotency_key=None):
163
+ return self.post(f"/developers/treasury/settlements/{settlement_id}/execute", payload or {}, idempotency_key=idempotency_key, token_type="dashboard")
164
+
165
+ def list_collections(self):
166
+ return self.get("/developers/collections", token_type="dashboard")
167
+
168
+ def create_collection(self, payload):
169
+ return self.post("/developers/collections", payload, token_type="dashboard")
170
+
171
+ def update_collection(self, collection_id, payload):
172
+ return self.patch(f"/developers/collections/{collection_id}", payload, token_type="dashboard")
173
+
174
+ def list_collection_payments(self, collection_id):
175
+ return self.get(f"/developers/collections/{collection_id}/payments", token_type="dashboard")
176
+
177
+ def public_collection(self, slug):
178
+ return self.get(f"/public/collections/{slug}", token_type="none")
179
+
180
+ def pay_collection(self, slug, payload):
181
+ return self.post(f"/public/collections/{slug}/pay", payload, token_type="none")
182
+
183
+ def update_settlement(self, payload):
184
+ return self.post("/developers/settlement", payload, token_type="dashboard")
185
+
186
+ def verify_settlement_account(self, payload):
187
+ return self.post("/developers/verify-account", payload, token_type="dashboard")
188
+
189
+ def kyc(self):
190
+ return self.get("/developers/kyc", token_type="dashboard")
191
+
192
+ def submit_kyc(self, payload):
193
+ return self.post("/developers/kyc", payload, token_type="dashboard")
194
+
195
+ def request_compliance_review(self, payload=None):
196
+ return self.post("/developers/compliance/request-review", payload or {}, token_type="dashboard")
197
+
198
+ @staticmethod
199
+ def parse_webhook(raw_body):
200
+ return json.loads(raw_body) if isinstance(raw_body, str) else raw_body
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "finswitz"
7
+ version = "1.0.0"
8
+ description = "Official Python SDK for the Finswitz API"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ authors = [
12
+ { name = "Finswitz" }
13
+ ]
14
+ requires-python = ">=3.8"
15
+ keywords = [
16
+ "payments",
17
+ "fintech",
18
+ "finswitz",
19
+ "api"
20
+ ]
21
+ classifiers = [
22
+ "Programming Language :: Python :: 3",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Operating System :: OS Independent"
25
+ ]
26
+
27
+ [tool.setuptools]
28
+ py-modules = ["finswitz"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+