kibonet-python-sdk 0.1.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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Jackson Linus
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.
@@ -0,0 +1,269 @@
1
+ Metadata-Version: 2.4
2
+ Name: kibonet-python-sdk
3
+ Version: 0.1.0
4
+ Summary: Simple, secure Python SDK for the KiboNet SMS Gateway
5
+ Author-email: Jackson Linus <jacksonlinus95@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/JAXPARROW/kibonet-python-sdk
8
+ Project-URL: Repository, https://github.com/JAXPARROW/kibonet-python-sdk.git
9
+ Project-URL: Issues, https://github.com/JAXPARROW/kibonet-python-sdk/issues
10
+ Keywords: kibonet,sms,tanzania,africa,messaging,httpx,async
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Communications :: Telephony
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Framework :: AsyncIO
22
+ Requires-Python: >=3.8
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: httpx>=0.24.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
28
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
29
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
30
+ Requires-Dist: respx>=0.20.0; extra == "dev"
31
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
32
+ Requires-Dist: black>=23.0.0; extra == "dev"
33
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
34
+ Requires-Dist: build>=1.0.0; extra == "dev"
35
+ Requires-Dist: twine>=4.0.0; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # KiboNet Python SDK
39
+
40
+ Simple, secure Python SDK for the [KiboNet SMS Gateway](https://sms.kibonet.co.tz).
41
+ Supports both **synchronous** and **async** usage via [httpx](https://www.python-httpx.org/).
42
+
43
+ [![PyPI version](https://img.shields.io/pypi/v/kibonet-python-sdk)](https://pypi.org/project/kibonet-python-sdk/)
44
+ [![Python Versions](https://img.shields.io/pypi/pyversions/kibonet-python-sdk)](https://pypi.org/project/kibonet-python-sdk/)
45
+ [![License: MIT](https://img.shields.io/pypi/l/kibonet-python-sdk)](https://pypi.org/project/kibonet-python-sdk/)
46
+
47
+ ## Features
48
+
49
+ - **Send SMS** to one or multiple recipients (comma-separated contacts)
50
+ - **Delivery reports** retrieved by `shootId`
51
+ - **Balance check** for your SMS credits
52
+ - **Health check** — `is_healthy()` never raises, perfect for monitoring probes
53
+ - **Async support** — full `async`/`await` via `AsyncKiboNetClient`
54
+ - **httpx** under the hood — connection pooling, automatic retries, TLS verification
55
+ - **Phone number validation** — auto-converts `0XXXXXXXXX` → `255XXXXXXXXX`
56
+ - **Typed exceptions** — catch exactly what you need
57
+ - **Context manager** support (both sync and async)
58
+ - **No credentials in code** — load from environment variables
59
+
60
+ ## Installation
61
+
62
+ ```bash
63
+ pip install kibonet-python-sdk
64
+ ```
65
+
66
+ ## Quick Start
67
+
68
+ ### Synchronous
69
+
70
+ ```python
71
+ from kibonet_sdk import KiboNetClient
72
+
73
+ with KiboNetClient(api_key="YOUR_API_KEY", api_secret="YOUR_API_SECRET") as client:
74
+ # Health check
75
+ if client.is_healthy():
76
+ print("API is up!")
77
+
78
+ # Send SMS
79
+ resp = client.send_sms(
80
+ sender_id="MyBrand",
81
+ message="Hello from KiboNet!",
82
+ contacts=["255712345678", "255798765432"],
83
+ delivery_report_url="https://myserver.com/delivery-callback", # optional
84
+ )
85
+ print(f"Shoot ID: {resp['data']['shootId']}")
86
+ print(f"Valid: {resp['data']['validContacts']}")
87
+ ```
88
+
89
+ ### Asynchronous
90
+
91
+ ```python
92
+ import asyncio
93
+ from kibonet_sdk import AsyncKiboNetClient
94
+
95
+ async def main():
96
+ async with AsyncKiboNetClient(api_key="YOUR_API_KEY", api_secret="YOUR_API_SECRET") as client:
97
+ if await client.is_healthy():
98
+ resp = await client.send_sms(
99
+ sender_id="MyBrand",
100
+ message="Hello async!",
101
+ contacts="255712345678",
102
+ )
103
+ print(resp["data"]["shootId"])
104
+
105
+ asyncio.run(main())
106
+ ```
107
+
108
+ ## All Methods
109
+
110
+ Both `KiboNetClient` and `AsyncKiboNetClient` expose the same interface:
111
+
112
+ ### `send_sms`
113
+
114
+ ```python
115
+ resp = client.send_sms(
116
+ sender_id="MyBrand", # Sender name shown to recipient
117
+ message="Your OTP is 1234", # SMS text
118
+ contacts=[ # Single string, list, or CSV string
119
+ "255712345678",
120
+ "255798765432",
121
+ ],
122
+ delivery_report_url="https://myserver.com/callback", # optional
123
+ message_type="text", # currently only "text" is supported
124
+ )
125
+
126
+ # Response
127
+ print(resp["data"]["shootId"]) # Use this for delivery reports
128
+ print(resp["data"]["validContacts"]) # int
129
+ print(resp["data"]["invalidContacts"]) # int
130
+ print(resp["data"]["duplicatedContacts"])
131
+ print(resp["data"]["messageSize"]) # character count
132
+ ```
133
+
134
+ ### `get_delivery_report`
135
+
136
+ ```python
137
+ report = client.get_delivery_report("abcd1234-5678-efgh-9012-ijklmnopqrst")
138
+
139
+ for record in report["data"]:
140
+ print(record["mobile"]) # 255712345678
141
+ print(record["status"]) # Delivered / Failed / Buffered
142
+ print(record["statusCode"]) # 000
143
+ print(record["sentAt"]) # "07-02-2024 07:35:08"
144
+ ```
145
+
146
+ ### `get_balance`
147
+
148
+ ```python
149
+ result = client.get_balance()
150
+ print(result["data"]["totalSms"]) # e.g. 30
151
+ ```
152
+
153
+ ### `is_healthy`
154
+
155
+ ```python
156
+ if client.is_healthy():
157
+ print("API is reachable and credentials are valid")
158
+ ```
159
+
160
+ ## Phone Number Formats
161
+
162
+ The SDK automatically normalises phone numbers:
163
+
164
+ | Input format | Stored as |
165
+ |--------------------|----------------|
166
+ | `0712345678` | `255712345678` |
167
+ | `+255712345678` | `255712345678` |
168
+ | `255712345678` | `255712345678` |
169
+
170
+ ## Error Handling
171
+
172
+ ```python
173
+ from kibonet_sdk import KiboNetClient
174
+ from kibonet_sdk.exceptions import (
175
+ KiboNetAuthenticationError,
176
+ KiboNetValidationError,
177
+ KiboNetRateLimitError,
178
+ KiboNetInsufficientBalanceError,
179
+ KiboNetConnectionError,
180
+ KiboNetServerError,
181
+ KiboNetAPIError,
182
+ KiboNetError, # base — catch everything SDK-related
183
+ )
184
+
185
+ client = KiboNetClient(api_key="...", api_secret="...")
186
+
187
+ try:
188
+ client.send_sms(sender_id="X", message="Hi", contacts="255712345678")
189
+ except KiboNetAuthenticationError:
190
+ print("Bad credentials")
191
+ except KiboNetValidationError as e:
192
+ print(f"Input error: {e}")
193
+ except KiboNetRateLimitError:
194
+ print("Slow down — rate limited")
195
+ except KiboNetConnectionError as e:
196
+ print(f"Network error: {e}")
197
+ except KiboNetServerError as e:
198
+ print(f"KiboNet server problem: {e}")
199
+ except KiboNetAPIError as e:
200
+ print(f"API error (code={e.code}): {e}")
201
+ ```
202
+
203
+ ## Environment Variables
204
+
205
+ Keep credentials out of source code:
206
+
207
+ ```bash
208
+ export KIBONET_API_KEY="your_api_key"
209
+ export KIBONET_API_SECRET="your_api_secret"
210
+ ```
211
+
212
+ ```python
213
+ import os
214
+ from kibonet_sdk import KiboNetClient
215
+
216
+ client = KiboNetClient(
217
+ api_key=os.environ["KIBONET_API_KEY"],
218
+ api_secret=os.environ["KIBONET_API_SECRET"],
219
+ )
220
+ ```
221
+
222
+ ## Constructor Options
223
+
224
+ ```python
225
+ KiboNetClient(
226
+ api_key: str, # Required — from KiboNet portal
227
+ api_secret: str, # Required — from KiboNet portal
228
+ timeout: float = 30.0, # Per-request timeout in seconds
229
+ max_retries: int = 3, # Automatic retries on transient failures
230
+ logger=None, # Optional logging.Logger
231
+ )
232
+ ```
233
+
234
+ `AsyncKiboNetClient` takes the same parameters.
235
+
236
+ ## Logging
237
+
238
+ ```python
239
+ import logging
240
+ logging.basicConfig(level=logging.DEBUG)
241
+
242
+ client = KiboNetClient(api_key="...", api_secret="...")
243
+ # All HTTP calls are logged at DEBUG level
244
+ ```
245
+
246
+ ## Development
247
+
248
+ ```bash
249
+ git clone https://github.com/JAXPARROW/kibonet-python-sdk.git
250
+ cd kibonet-python-sdk
251
+ pip install -e ".[dev]"
252
+
253
+ # Run tests
254
+ pytest
255
+
256
+ # Run with coverage
257
+ pytest --cov=kibonet_sdk --cov-report=term-missing
258
+
259
+ # Build
260
+ python -m build
261
+ ```
262
+
263
+ ## License
264
+
265
+ MIT — see [LICENSE](LICENSE).
266
+
267
+ ## Contributors
268
+
269
+ - **Jackson Linus** — Creator and maintainer
@@ -0,0 +1,232 @@
1
+ # KiboNet Python SDK
2
+
3
+ Simple, secure Python SDK for the [KiboNet SMS Gateway](https://sms.kibonet.co.tz).
4
+ Supports both **synchronous** and **async** usage via [httpx](https://www.python-httpx.org/).
5
+
6
+ [![PyPI version](https://img.shields.io/pypi/v/kibonet-python-sdk)](https://pypi.org/project/kibonet-python-sdk/)
7
+ [![Python Versions](https://img.shields.io/pypi/pyversions/kibonet-python-sdk)](https://pypi.org/project/kibonet-python-sdk/)
8
+ [![License: MIT](https://img.shields.io/pypi/l/kibonet-python-sdk)](https://pypi.org/project/kibonet-python-sdk/)
9
+
10
+ ## Features
11
+
12
+ - **Send SMS** to one or multiple recipients (comma-separated contacts)
13
+ - **Delivery reports** retrieved by `shootId`
14
+ - **Balance check** for your SMS credits
15
+ - **Health check** — `is_healthy()` never raises, perfect for monitoring probes
16
+ - **Async support** — full `async`/`await` via `AsyncKiboNetClient`
17
+ - **httpx** under the hood — connection pooling, automatic retries, TLS verification
18
+ - **Phone number validation** — auto-converts `0XXXXXXXXX` → `255XXXXXXXXX`
19
+ - **Typed exceptions** — catch exactly what you need
20
+ - **Context manager** support (both sync and async)
21
+ - **No credentials in code** — load from environment variables
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install kibonet-python-sdk
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ### Synchronous
32
+
33
+ ```python
34
+ from kibonet_sdk import KiboNetClient
35
+
36
+ with KiboNetClient(api_key="YOUR_API_KEY", api_secret="YOUR_API_SECRET") as client:
37
+ # Health check
38
+ if client.is_healthy():
39
+ print("API is up!")
40
+
41
+ # Send SMS
42
+ resp = client.send_sms(
43
+ sender_id="MyBrand",
44
+ message="Hello from KiboNet!",
45
+ contacts=["255712345678", "255798765432"],
46
+ delivery_report_url="https://myserver.com/delivery-callback", # optional
47
+ )
48
+ print(f"Shoot ID: {resp['data']['shootId']}")
49
+ print(f"Valid: {resp['data']['validContacts']}")
50
+ ```
51
+
52
+ ### Asynchronous
53
+
54
+ ```python
55
+ import asyncio
56
+ from kibonet_sdk import AsyncKiboNetClient
57
+
58
+ async def main():
59
+ async with AsyncKiboNetClient(api_key="YOUR_API_KEY", api_secret="YOUR_API_SECRET") as client:
60
+ if await client.is_healthy():
61
+ resp = await client.send_sms(
62
+ sender_id="MyBrand",
63
+ message="Hello async!",
64
+ contacts="255712345678",
65
+ )
66
+ print(resp["data"]["shootId"])
67
+
68
+ asyncio.run(main())
69
+ ```
70
+
71
+ ## All Methods
72
+
73
+ Both `KiboNetClient` and `AsyncKiboNetClient` expose the same interface:
74
+
75
+ ### `send_sms`
76
+
77
+ ```python
78
+ resp = client.send_sms(
79
+ sender_id="MyBrand", # Sender name shown to recipient
80
+ message="Your OTP is 1234", # SMS text
81
+ contacts=[ # Single string, list, or CSV string
82
+ "255712345678",
83
+ "255798765432",
84
+ ],
85
+ delivery_report_url="https://myserver.com/callback", # optional
86
+ message_type="text", # currently only "text" is supported
87
+ )
88
+
89
+ # Response
90
+ print(resp["data"]["shootId"]) # Use this for delivery reports
91
+ print(resp["data"]["validContacts"]) # int
92
+ print(resp["data"]["invalidContacts"]) # int
93
+ print(resp["data"]["duplicatedContacts"])
94
+ print(resp["data"]["messageSize"]) # character count
95
+ ```
96
+
97
+ ### `get_delivery_report`
98
+
99
+ ```python
100
+ report = client.get_delivery_report("abcd1234-5678-efgh-9012-ijklmnopqrst")
101
+
102
+ for record in report["data"]:
103
+ print(record["mobile"]) # 255712345678
104
+ print(record["status"]) # Delivered / Failed / Buffered
105
+ print(record["statusCode"]) # 000
106
+ print(record["sentAt"]) # "07-02-2024 07:35:08"
107
+ ```
108
+
109
+ ### `get_balance`
110
+
111
+ ```python
112
+ result = client.get_balance()
113
+ print(result["data"]["totalSms"]) # e.g. 30
114
+ ```
115
+
116
+ ### `is_healthy`
117
+
118
+ ```python
119
+ if client.is_healthy():
120
+ print("API is reachable and credentials are valid")
121
+ ```
122
+
123
+ ## Phone Number Formats
124
+
125
+ The SDK automatically normalises phone numbers:
126
+
127
+ | Input format | Stored as |
128
+ |--------------------|----------------|
129
+ | `0712345678` | `255712345678` |
130
+ | `+255712345678` | `255712345678` |
131
+ | `255712345678` | `255712345678` |
132
+
133
+ ## Error Handling
134
+
135
+ ```python
136
+ from kibonet_sdk import KiboNetClient
137
+ from kibonet_sdk.exceptions import (
138
+ KiboNetAuthenticationError,
139
+ KiboNetValidationError,
140
+ KiboNetRateLimitError,
141
+ KiboNetInsufficientBalanceError,
142
+ KiboNetConnectionError,
143
+ KiboNetServerError,
144
+ KiboNetAPIError,
145
+ KiboNetError, # base — catch everything SDK-related
146
+ )
147
+
148
+ client = KiboNetClient(api_key="...", api_secret="...")
149
+
150
+ try:
151
+ client.send_sms(sender_id="X", message="Hi", contacts="255712345678")
152
+ except KiboNetAuthenticationError:
153
+ print("Bad credentials")
154
+ except KiboNetValidationError as e:
155
+ print(f"Input error: {e}")
156
+ except KiboNetRateLimitError:
157
+ print("Slow down — rate limited")
158
+ except KiboNetConnectionError as e:
159
+ print(f"Network error: {e}")
160
+ except KiboNetServerError as e:
161
+ print(f"KiboNet server problem: {e}")
162
+ except KiboNetAPIError as e:
163
+ print(f"API error (code={e.code}): {e}")
164
+ ```
165
+
166
+ ## Environment Variables
167
+
168
+ Keep credentials out of source code:
169
+
170
+ ```bash
171
+ export KIBONET_API_KEY="your_api_key"
172
+ export KIBONET_API_SECRET="your_api_secret"
173
+ ```
174
+
175
+ ```python
176
+ import os
177
+ from kibonet_sdk import KiboNetClient
178
+
179
+ client = KiboNetClient(
180
+ api_key=os.environ["KIBONET_API_KEY"],
181
+ api_secret=os.environ["KIBONET_API_SECRET"],
182
+ )
183
+ ```
184
+
185
+ ## Constructor Options
186
+
187
+ ```python
188
+ KiboNetClient(
189
+ api_key: str, # Required — from KiboNet portal
190
+ api_secret: str, # Required — from KiboNet portal
191
+ timeout: float = 30.0, # Per-request timeout in seconds
192
+ max_retries: int = 3, # Automatic retries on transient failures
193
+ logger=None, # Optional logging.Logger
194
+ )
195
+ ```
196
+
197
+ `AsyncKiboNetClient` takes the same parameters.
198
+
199
+ ## Logging
200
+
201
+ ```python
202
+ import logging
203
+ logging.basicConfig(level=logging.DEBUG)
204
+
205
+ client = KiboNetClient(api_key="...", api_secret="...")
206
+ # All HTTP calls are logged at DEBUG level
207
+ ```
208
+
209
+ ## Development
210
+
211
+ ```bash
212
+ git clone https://github.com/JAXPARROW/kibonet-python-sdk.git
213
+ cd kibonet-python-sdk
214
+ pip install -e ".[dev]"
215
+
216
+ # Run tests
217
+ pytest
218
+
219
+ # Run with coverage
220
+ pytest --cov=kibonet_sdk --cov-report=term-missing
221
+
222
+ # Build
223
+ python -m build
224
+ ```
225
+
226
+ ## License
227
+
228
+ MIT — see [LICENSE](LICENSE).
229
+
230
+ ## Contributors
231
+
232
+ - **Jackson Linus** — Creator and maintainer
@@ -0,0 +1,66 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "kibonet-python-sdk"
7
+ version = "0.1.0"
8
+ description = "Simple, secure Python SDK for the KiboNet SMS Gateway"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ authors = [
12
+ {name = "Jackson Linus", email = "jacksonlinus95@gmail.com"}
13
+ ]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.8",
19
+ "Programming Language :: Python :: 3.9",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Topic :: Communications :: Telephony",
24
+ "Topic :: Software Development :: Libraries :: Python Modules",
25
+ "Framework :: AsyncIO",
26
+ ]
27
+ keywords = ["kibonet", "sms", "tanzania", "africa", "messaging", "httpx", "async"]
28
+ dependencies = [
29
+ "httpx>=0.24.0",
30
+ ]
31
+ requires-python = ">=3.8"
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/JAXPARROW/kibonet-python-sdk"
35
+ Repository = "https://github.com/JAXPARROW/kibonet-python-sdk.git"
36
+ Issues = "https://github.com/JAXPARROW/kibonet-python-sdk/issues"
37
+
38
+ [project.optional-dependencies]
39
+ dev = [
40
+ "pytest>=7.0.0",
41
+ "pytest-asyncio>=0.21.0",
42
+ "pytest-cov>=4.0.0",
43
+ "respx>=0.20.0",
44
+ "mypy>=1.0.0",
45
+ "black>=23.0.0",
46
+ "ruff>=0.1.0",
47
+ "build>=1.0.0",
48
+ "twine>=4.0.0",
49
+ ]
50
+
51
+ [tool.setuptools.packages.find]
52
+ where = ["src"]
53
+ include = ["kibonet_sdk*"]
54
+
55
+ [tool.pytest.ini_options]
56
+ asyncio_mode = "auto"
57
+ testpaths = ["tests"]
58
+
59
+ [tool.mypy]
60
+ python_version = "3.8"
61
+ strict = true
62
+ ignore_missing_imports = true
63
+
64
+ [tool.ruff]
65
+ line-length = 100
66
+ target-version = "py38"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+