gava-connect-plus 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,248 @@
1
+ Metadata-Version: 2.3
2
+ Name: gava-connect-plus
3
+ Version: 0.1.0
4
+ Summary: Async-first production-grade SDK for Kenya's GavaConnect Enterprise API platform.
5
+ Author: Erick
6
+ Author-email: Erick <hearteric57@gmail.com>
7
+ Requires-Dist: blessed>=1.44.0
8
+ Requires-Dist: httpx>=0.28.1
9
+ Requires-Dist: pydantic>=2.13.4
10
+ Requires-Dist: pytest>=9.1.1
11
+ Requires-Dist: respx>=0.23.1
12
+ Requires-Python: >=3.11
13
+ Description-Content-Type: text/markdown
14
+
15
+ <p align="center">
16
+ <img alt="gava-connect-plus banner" src="https://raw.githubusercontent.com/IamMuuo/gava-connect-plus/master/assets/github-header-banner.png" width="100%" />
17
+ </p>
18
+
19
+ <p align="center">
20
+ <picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/flag/ke.svg?theme=gray" /><img alt="built in" src="https://shieldcn.dev/flag/ke.svg?theme=gray&amp;mode=light" /></picture>
21
+ <a href="https://github.com/iammuuo/gava-connect-plus"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/github/iammuuo/gava-connect-plus/license.svg?theme=green" /><img alt="license" src="https://shieldcn.dev/github/iammuuo/gava-connect-plus/license.svg?theme=green&amp;mode=light" /></picture></a>
22
+ <a href="https://github.com/iammuuo/gava-connect-plus/commits"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/github/iammuuo/gava-connect-plus/last-commit.svg?theme=cyan" /><img alt="last commit" src="https://shieldcn.dev/github/iammuuo/gava-connect-plus/last-commit.svg?theme=cyan&amp;mode=light" /></picture></a>
23
+ <a href="https://github.com/iammuuo/gava-connect-plus/actions"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/github/iammuuo/gava-connect-plus/ci.svg" /><img alt="CI" src="https://shieldcn.dev/github/iammuuo/gava-connect-plus/ci.svg?mode=light" /></picture></a>
24
+ <a href="https://github.com/iammuuo/gava-connect-plus/graphs/contributors"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/github/iammuuo/gava-connect-plus/contributors.svg" /><img alt="contributors" src="https://shieldcn.dev/github/iammuuo/gava-connect-plus/contributors.svg?mode=light" /></picture></a>
25
+ <a href="https://github.com/iammuuo/gava-connect-plus"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/github/iammuuo/gava-connect-plus/stars.svg?theme=rose" /><img alt="stars" src="https://shieldcn.dev/github/iammuuo/gava-connect-plus/stars.svg?theme=rose&amp;mode=light" /></picture></a>
26
+ </p>
27
+
28
+ # gava-connect-plus
29
+
30
+ Every Kenyan developer who has built an e-commerce platform, an accounting tool, or a payroll system eventually faces the same formidable milestone: integrating with the Kenya Revenue Authority (KRA) APIs.
31
+
32
+ Historically, this meant wading through fragmented PDF documentation, wrestling with clunky authentication flows, and writing thousands of lines of fragile boilerplate just to check if a PIN is valid or an eTIMS invoice is authentic. The process wasn't just slow—it was a tax on developer sanity.
33
+
34
+ gava-connect-plus was born out of a simple, rebellious realization: Integrating with local compliance infrastructure shouldn't feel like standing in a physical KRA line. This library serves as a beautiful, unofficial bridge between modern Python applications and the government gateway—built to handle the heavy lifting of compliance safely, invisibly, and instantly.
35
+
36
+ ## Core Principles
37
+
38
+ The architecture of gava-connect-plus is guided by three simple truths:
39
+
40
+
41
+ ### 1. Developer Zen
42
+
43
+ The code you write should look like clean Python, not government bureaucracy. Complex SOAP/REST structures, weird payload mappings, and authentication handshakes are abstracted away behind an elegant, predictable API surface. One method call does exactly what it says.
44
+
45
+ ### 2. Radical Isolation
46
+
47
+ Security is peace of mind. Every corporate department or microservice deserves its own cryptographic boundaries. By keeping service credentials strictly isolated (Invoice, PIN, and Station each running on their own terms), the library prevents permission creep and ensures your production tokens never bleed into one another.
48
+
49
+ ### 3. Execution "Chap Chap"
50
+
51
+ Time is the only non-renewable asset. Whether running automated testing pipelines in the cloud or deploying to live production, the library is lightweight, optimized, and zero-fluff. It does its job and gets out of your way.
52
+
53
+
54
+ ## Installation & Quick Start
55
+
56
+ True to the principle of execution chap chap, getting the library into your environment takes a single command. We recommend using uv for lightning-fast environment resolution, but standard tools work perfectly too.
57
+
58
+ ```bash
59
+ # For the mordenist usinv uv
60
+ uv add gava-connect-plus
61
+
62
+ # The classic way
63
+ pip install gava-connect-plus
64
+ ```
65
+
66
+
67
+ ### Obtaining passwords, keys etc
68
+
69
+ Before writing any code, you need to secure your cryptographic credentials from the official gateway ecosystem.
70
+ 1. Head over to the Kenyan Government [Developer Portal](https://developer.go.ke/).
71
+ 2. Register an account and navigate to your dashboard workspace to provision access keys.
72
+
73
+ > Tutorials for obtaining passwords available on youtube and beyond the scope of this doc
74
+
75
+ ### The Multi-App Architecture (Crucial Note)
76
+
77
+ The KRA API gateway relies on strict security scoping. Permissions are segregated at the application layer rather than bundled into a single master key. This means credentials must be obtained per module/API.
78
+
79
+ If your software requires both taxpayer identity verification and invoice tracking, you cannot use a single client key. You must create two separate applications inside the portal:
80
+
81
+ - App #1: Provisioned explicitly with the `PIN Checker by PIN` scope.
82
+ - App #2: Provisioned explicitly with the `Invoice Checker` scope.
83
+
84
+ Once you have your isolated keys, gava-connect-plus takes complete control of the administrative mess.
85
+
86
+ **The Promise**: You do not need to worry about the underlying Authorization endpoints, token expiration thresholds, or handshake state machines. Once the library is supplied with your application keys, internal OAuth token provisioning, caching, and background refreshes are executed seamlessly on autopilot.
87
+
88
+ ## 1. Configure the Environment Sanctuary
89
+ Expose your isolated sandbox or production credential pairs directly to your system shell thread. The library automatically tracks these exact environment keys, keeping your production secrets completely out of source control:
90
+
91
+ ```bash
92
+ # App #1: PIN Validation Credentials
93
+ export KRA_PIN_KEY="your_pin_app_consumer_key"
94
+ export KRA_PIN_SECRET="your_pin_app_consumer_secret"
95
+
96
+ # App #2: eTIMS Invoice Credentials
97
+ export KRA_INVOICE_KEY="your_invoice_app_consumer_key"
98
+ export KRA_INVOICE_SECRET="your_invoice_app_consumer_secret"
99
+ ```
100
+
101
+ ## 2. Write Pure, Frictionless Python
102
+ With your system environments aligned, initialize the workspace context. The library dynamically routes internal token handshakes to their respective apps in the background based on the API you invoke.
103
+
104
+ ```python
105
+ from gavaconnect import GavaConnect
106
+ from gavaconnect.exceptions import GavaConnectError
107
+
108
+ # Initialize the engine targeting the KRA gateway sandbox
109
+ with GavaConnect(environment="sandbox") as gava:
110
+ try:
111
+ # Validates identity via your PIN-scoped application keys
112
+ record = gava.pin.check("A001234567Z")
113
+ print(f"Identity Verified: {record.taxpayer_name}")
114
+
115
+ # Audits eTIMS status via your Invoice-scoped application keys
116
+ # All background OAuth tokens swap silently behind the scenes
117
+ invoice = gava.invoice.get("INV-99824-X")
118
+ print(f"Gross Invoice Value: KES {invoice.total_invoice_amount:,.2f}")
119
+
120
+ except GavaConnectError as e:
121
+ print(f"The gateway returned a peaceful error: {e}")
122
+ ```
123
+
124
+ ## 3. Explicit Dependency Injection (Alternative)
125
+
126
+ If you are managing configuration objects programmatically at runtime (e.g., retrieving secrets from an encrypted vault), bypass the environment variables by injecting the multi-app map dictionary directly into the builder constructor:
127
+
128
+ ```python
129
+ from gavaconnect import GavaConnect
130
+
131
+ # Map explicit credentials precisely to their module domain targets
132
+ custom_config = {
133
+ "pin": {
134
+ "consumer_key": "vault_pin_key_xyz",
135
+ "consumer_secret": "vault_pin_secret_abc"
136
+ },
137
+ "invoice": {
138
+ "consumer_key": "vault_invoice_key_123",
139
+ "consumer_secret": "vault_invoice_secret_789"
140
+ }
141
+ }
142
+
143
+ with GavaConnect(environment="sandbox", **custom_config) as gava:
144
+ station = gava.station.get("A001234567Z")
145
+ print(f"Assigned Tax Station: {station.station_name}")
146
+ ```
147
+
148
+ ---
149
+
150
+ # A word about using the library
151
+
152
+ ## Sync & Async Harmony
153
+
154
+ Python architectures are diverse. Some systems demand the raw speed of non-blocking concurrency, while others require the rock-solid predictability of standard sequential execution. `gava-connect-plus` honors both paths by providing native, separate engines for both synchronous and asynchronous workflows.
155
+
156
+ When initializing the library, you can choose the engine that perfectly aligns with your environment constraints and runtime architecture.
157
+
158
+ ### The Asynchronous Path (For High-Concurrence API Gateways)
159
+ If you are building high-throughput microservices using modern async frameworks like FastAPI, Litestar, or Sanic, use the async flavor to ensure your application threads never sleep while waiting for network I/O from the KRA gateway:
160
+
161
+ ```python
162
+ import asyncio
163
+ from gavaconnect import GavaConnect
164
+
165
+ async def main():
166
+ # Non-blocking connection pooling executing natively inside your event loop
167
+ async with GavaConnectAsync(environment="sandbox") as gava:
168
+ record = await gava.pin.check("A001234567Z")
169
+ print(f"Async Identity Verified: {record.taxpayer_name}")
170
+
171
+ asyncio.run(main())
172
+ ```
173
+
174
+ ### The Synchronous Path (For Predictable, Thread-Safe Workflows)
175
+
176
+ For applications built on standard blocking architectures, the synchronous engine provides a clean, dependency-free wrapper that executes line-by-line without an active event loop loop manager:
177
+
178
+ ```python
179
+ from gavaconnect import GavaConnectSync
180
+
181
+ with GavaConnect(environment="sandbox") as gava:
182
+ record = gava.pin.check("A001234567Z")
183
+ print(f"Sync Identity Verified: {record.taxpayer_name}")
184
+
185
+ ```
186
+
187
+ ### Architectural Nuance: When to stay Synchronous (The Django Paradigm)
188
+
189
+ It is tempting to default to async for all network utilities, but context dictates performance. For example, if you are integrating this library into a traditional Django application served via a standard WSGI stack (like Gunicorn or uWSGI), you should choose the synchronous version.
190
+
191
+ The Technical Reason: Django’s core engine, request lifecycle middlewares, and database ORM layers are fundamentally synchronous by design. While Django offers async views, mixing them into a WSGI runtime forces the framework to wrap execution threads in thread-switching utility layers (`async_to_sync` and `sync_to_async`).
192
+
193
+ If your view is already handling a synchronous database transaction, throwing an asynchronous API call into the middle of it triggers complex context-switching overhead and thread hopping inside the Python runtime. This context switching can actually degrade performance and introduce subtle race conditions with thread-local data. Staying purely synchronous inside a synchronous application architecture keeps your execution path flat, memory overhead minimal, and debugging straightforward.
194
+
195
+ ---
196
+
197
+ # Path to Completeness (Module Roadmap)
198
+ The KRA API ecosystem is vast, covering everything from basic identity checks to complex customs calculations and tax filing routines. Rome wasn't built in a day, and neither is the ultimate developer gateway toolkit.
199
+
200
+ gava-connect-plus is a living blueprint. While the core verification bedrock is fully operational and production-ready, several advanced transactional modules are currently slated for future integration cycles.
201
+
202
+ Below is the current state of alignment between the SDK and the official developer.go.ke portal services:
203
+
204
+
205
+
206
+ <div align="center">
207
+
208
+ | Feature / API Endpoint | Status | Tested |
209
+ | --- | --- | :---: |
210
+ | Automated OAuth Token Lifecycle Management & Caching | ✅ | ✅ |
211
+ | PIN Checker by PIN (`PIN_Validation_by_PIN`) | ✅ | ✅ |
212
+ | PIN Checker by ID (`DTD_PINChecker`) | ✅ | ✅ |
213
+ | Know KRA Tax Service Office/Station (`SUC-iTax-USSD_Know_Your_Station`) | ✅ | ✅ |
214
+ | eTIMS Invoice Checker (`Invoice-Checker`) | ✅ | ✅ |
215
+ | Fetch Taxpayer Obligations (`TaxPayer_Tax_Obligations_Fetcher`) | ⏳ Planned | - |
216
+ | Withholding Tax PRN Generation (Income Tax, Rental, VAT) | ⏳ Planned | - |
217
+ | Tax Compliance Certificate (TCC) Validation & Application | ⏳ Planned | - |
218
+ | Automated NIL Return Filing (`iTax_NIL_Return`) | ⏳ Planned | - |
219
+ | Income Tax & VAT Exemption Checker | ⏳ Planned | - |
220
+ | Turnover Tax (TOT) Return Filing | ⏳ Planned | - |
221
+ | Customs Declaration Status Checker & Tax Calculator | ⏳ Planned | - |
222
+ | Import Certificate Checker (By Number / PIN) | ⏳ Planned | - |
223
+ | Individual KRA PIN Registration Gateway | ⏳ Planned | - |
224
+ | eTIMS OSCU Integrator Automated Testing Suite | ⏳ Planned | - |
225
+ | Excise License Checker (By Pin / Certificate Number) | ⏳ Planned | - |
226
+
227
+ </div>
228
+
229
+ # The Genesis & Contributing
230
+
231
+ Let’s clear the air right away: I am not affiliated, associated, authorized, or in any way officially connected with the Kenya Revenue Authority (KRA). This project was born out of pure, unadulterated developer frustration. While building a commercial product that required KRA portal integrations, I looked around the ecosystem for a robust, production-grade Python package that could handle the gateway safely and seamlessly. I found absolutely nothing.
232
+
233
+ Faced with a wall of fragmented PDFs and custom network scripts, I decided to take a deep breath, skip a few nights of sleep, and jump straight down the rabbit hole to build the tool that should have already existed. `gava-connect-plus` is the result of that journey.
234
+
235
+ ## Join the Journey
236
+ Because this is a community-driven initiative, your hands and minds are needed to help shape it. Whether you want to squash an edge-case bug, optimize the internal caching layers, or drag one of the *Planned transactional* modules into operational reality, contributions are deeply welcomed.
237
+
238
+ Feel free to open an issue, start a discussion thread, or send a pull request over the wall. Let's make integration painless for the next developer.
239
+
240
+ ## Support the energy
241
+ If gava-connect-plus saves you days of digging through portal specifications, keeps your production builds green, or spares your team a minor existential crisis, consider giving back to the project:
242
+ - **⭐ Star the Repository**: It costs nothing and directly helps other Kenyan developers discover the project on GitHub.
243
+ - **🗣️ Spread the Word**: Share the project link in your local tech WhatsApp groups, Discord servers, or on X (Twitter). Let's build a stronger local open-source culture.
244
+ - **☕ Buy Me a Coffee**: If this library saved your business real billable hours, consider fueling the midnight oil for the next sprint of module developments. Your support keeps the zen flowing.
245
+
246
+ <p align="center">
247
+ <picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/chart/github/stars/iammuuo/gava-connect-plus.svg?theme=green&amp;font=geist&amp;title=Github+stars+over+time&amp;icon=refinedgithub" /><img alt="chart" src="https://shieldcn.dev/chart/github/stars/iammuuo/gava-connect-plus.svg?mode=light&amp;theme=green&amp;font=geist&amp;title=Github+stars+over+time&amp;icon=refinedgithub" /></picture>
248
+ </p>
@@ -0,0 +1,234 @@
1
+ <p align="center">
2
+ <img alt="gava-connect-plus banner" src="https://raw.githubusercontent.com/IamMuuo/gava-connect-plus/master/assets/github-header-banner.png" width="100%" />
3
+ </p>
4
+
5
+ <p align="center">
6
+ <picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/flag/ke.svg?theme=gray" /><img alt="built in" src="https://shieldcn.dev/flag/ke.svg?theme=gray&amp;mode=light" /></picture>
7
+ <a href="https://github.com/iammuuo/gava-connect-plus"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/github/iammuuo/gava-connect-plus/license.svg?theme=green" /><img alt="license" src="https://shieldcn.dev/github/iammuuo/gava-connect-plus/license.svg?theme=green&amp;mode=light" /></picture></a>
8
+ <a href="https://github.com/iammuuo/gava-connect-plus/commits"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/github/iammuuo/gava-connect-plus/last-commit.svg?theme=cyan" /><img alt="last commit" src="https://shieldcn.dev/github/iammuuo/gava-connect-plus/last-commit.svg?theme=cyan&amp;mode=light" /></picture></a>
9
+ <a href="https://github.com/iammuuo/gava-connect-plus/actions"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/github/iammuuo/gava-connect-plus/ci.svg" /><img alt="CI" src="https://shieldcn.dev/github/iammuuo/gava-connect-plus/ci.svg?mode=light" /></picture></a>
10
+ <a href="https://github.com/iammuuo/gava-connect-plus/graphs/contributors"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/github/iammuuo/gava-connect-plus/contributors.svg" /><img alt="contributors" src="https://shieldcn.dev/github/iammuuo/gava-connect-plus/contributors.svg?mode=light" /></picture></a>
11
+ <a href="https://github.com/iammuuo/gava-connect-plus"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/github/iammuuo/gava-connect-plus/stars.svg?theme=rose" /><img alt="stars" src="https://shieldcn.dev/github/iammuuo/gava-connect-plus/stars.svg?theme=rose&amp;mode=light" /></picture></a>
12
+ </p>
13
+
14
+ # gava-connect-plus
15
+
16
+ Every Kenyan developer who has built an e-commerce platform, an accounting tool, or a payroll system eventually faces the same formidable milestone: integrating with the Kenya Revenue Authority (KRA) APIs.
17
+
18
+ Historically, this meant wading through fragmented PDF documentation, wrestling with clunky authentication flows, and writing thousands of lines of fragile boilerplate just to check if a PIN is valid or an eTIMS invoice is authentic. The process wasn't just slow—it was a tax on developer sanity.
19
+
20
+ gava-connect-plus was born out of a simple, rebellious realization: Integrating with local compliance infrastructure shouldn't feel like standing in a physical KRA line. This library serves as a beautiful, unofficial bridge between modern Python applications and the government gateway—built to handle the heavy lifting of compliance safely, invisibly, and instantly.
21
+
22
+ ## Core Principles
23
+
24
+ The architecture of gava-connect-plus is guided by three simple truths:
25
+
26
+
27
+ ### 1. Developer Zen
28
+
29
+ The code you write should look like clean Python, not government bureaucracy. Complex SOAP/REST structures, weird payload mappings, and authentication handshakes are abstracted away behind an elegant, predictable API surface. One method call does exactly what it says.
30
+
31
+ ### 2. Radical Isolation
32
+
33
+ Security is peace of mind. Every corporate department or microservice deserves its own cryptographic boundaries. By keeping service credentials strictly isolated (Invoice, PIN, and Station each running on their own terms), the library prevents permission creep and ensures your production tokens never bleed into one another.
34
+
35
+ ### 3. Execution "Chap Chap"
36
+
37
+ Time is the only non-renewable asset. Whether running automated testing pipelines in the cloud or deploying to live production, the library is lightweight, optimized, and zero-fluff. It does its job and gets out of your way.
38
+
39
+
40
+ ## Installation & Quick Start
41
+
42
+ True to the principle of execution chap chap, getting the library into your environment takes a single command. We recommend using uv for lightning-fast environment resolution, but standard tools work perfectly too.
43
+
44
+ ```bash
45
+ # For the mordenist usinv uv
46
+ uv add gava-connect-plus
47
+
48
+ # The classic way
49
+ pip install gava-connect-plus
50
+ ```
51
+
52
+
53
+ ### Obtaining passwords, keys etc
54
+
55
+ Before writing any code, you need to secure your cryptographic credentials from the official gateway ecosystem.
56
+ 1. Head over to the Kenyan Government [Developer Portal](https://developer.go.ke/).
57
+ 2. Register an account and navigate to your dashboard workspace to provision access keys.
58
+
59
+ > Tutorials for obtaining passwords available on youtube and beyond the scope of this doc
60
+
61
+ ### The Multi-App Architecture (Crucial Note)
62
+
63
+ The KRA API gateway relies on strict security scoping. Permissions are segregated at the application layer rather than bundled into a single master key. This means credentials must be obtained per module/API.
64
+
65
+ If your software requires both taxpayer identity verification and invoice tracking, you cannot use a single client key. You must create two separate applications inside the portal:
66
+
67
+ - App #1: Provisioned explicitly with the `PIN Checker by PIN` scope.
68
+ - App #2: Provisioned explicitly with the `Invoice Checker` scope.
69
+
70
+ Once you have your isolated keys, gava-connect-plus takes complete control of the administrative mess.
71
+
72
+ **The Promise**: You do not need to worry about the underlying Authorization endpoints, token expiration thresholds, or handshake state machines. Once the library is supplied with your application keys, internal OAuth token provisioning, caching, and background refreshes are executed seamlessly on autopilot.
73
+
74
+ ## 1. Configure the Environment Sanctuary
75
+ Expose your isolated sandbox or production credential pairs directly to your system shell thread. The library automatically tracks these exact environment keys, keeping your production secrets completely out of source control:
76
+
77
+ ```bash
78
+ # App #1: PIN Validation Credentials
79
+ export KRA_PIN_KEY="your_pin_app_consumer_key"
80
+ export KRA_PIN_SECRET="your_pin_app_consumer_secret"
81
+
82
+ # App #2: eTIMS Invoice Credentials
83
+ export KRA_INVOICE_KEY="your_invoice_app_consumer_key"
84
+ export KRA_INVOICE_SECRET="your_invoice_app_consumer_secret"
85
+ ```
86
+
87
+ ## 2. Write Pure, Frictionless Python
88
+ With your system environments aligned, initialize the workspace context. The library dynamically routes internal token handshakes to their respective apps in the background based on the API you invoke.
89
+
90
+ ```python
91
+ from gavaconnect import GavaConnect
92
+ from gavaconnect.exceptions import GavaConnectError
93
+
94
+ # Initialize the engine targeting the KRA gateway sandbox
95
+ with GavaConnect(environment="sandbox") as gava:
96
+ try:
97
+ # Validates identity via your PIN-scoped application keys
98
+ record = gava.pin.check("A001234567Z")
99
+ print(f"Identity Verified: {record.taxpayer_name}")
100
+
101
+ # Audits eTIMS status via your Invoice-scoped application keys
102
+ # All background OAuth tokens swap silently behind the scenes
103
+ invoice = gava.invoice.get("INV-99824-X")
104
+ print(f"Gross Invoice Value: KES {invoice.total_invoice_amount:,.2f}")
105
+
106
+ except GavaConnectError as e:
107
+ print(f"The gateway returned a peaceful error: {e}")
108
+ ```
109
+
110
+ ## 3. Explicit Dependency Injection (Alternative)
111
+
112
+ If you are managing configuration objects programmatically at runtime (e.g., retrieving secrets from an encrypted vault), bypass the environment variables by injecting the multi-app map dictionary directly into the builder constructor:
113
+
114
+ ```python
115
+ from gavaconnect import GavaConnect
116
+
117
+ # Map explicit credentials precisely to their module domain targets
118
+ custom_config = {
119
+ "pin": {
120
+ "consumer_key": "vault_pin_key_xyz",
121
+ "consumer_secret": "vault_pin_secret_abc"
122
+ },
123
+ "invoice": {
124
+ "consumer_key": "vault_invoice_key_123",
125
+ "consumer_secret": "vault_invoice_secret_789"
126
+ }
127
+ }
128
+
129
+ with GavaConnect(environment="sandbox", **custom_config) as gava:
130
+ station = gava.station.get("A001234567Z")
131
+ print(f"Assigned Tax Station: {station.station_name}")
132
+ ```
133
+
134
+ ---
135
+
136
+ # A word about using the library
137
+
138
+ ## Sync & Async Harmony
139
+
140
+ Python architectures are diverse. Some systems demand the raw speed of non-blocking concurrency, while others require the rock-solid predictability of standard sequential execution. `gava-connect-plus` honors both paths by providing native, separate engines for both synchronous and asynchronous workflows.
141
+
142
+ When initializing the library, you can choose the engine that perfectly aligns with your environment constraints and runtime architecture.
143
+
144
+ ### The Asynchronous Path (For High-Concurrence API Gateways)
145
+ If you are building high-throughput microservices using modern async frameworks like FastAPI, Litestar, or Sanic, use the async flavor to ensure your application threads never sleep while waiting for network I/O from the KRA gateway:
146
+
147
+ ```python
148
+ import asyncio
149
+ from gavaconnect import GavaConnect
150
+
151
+ async def main():
152
+ # Non-blocking connection pooling executing natively inside your event loop
153
+ async with GavaConnectAsync(environment="sandbox") as gava:
154
+ record = await gava.pin.check("A001234567Z")
155
+ print(f"Async Identity Verified: {record.taxpayer_name}")
156
+
157
+ asyncio.run(main())
158
+ ```
159
+
160
+ ### The Synchronous Path (For Predictable, Thread-Safe Workflows)
161
+
162
+ For applications built on standard blocking architectures, the synchronous engine provides a clean, dependency-free wrapper that executes line-by-line without an active event loop loop manager:
163
+
164
+ ```python
165
+ from gavaconnect import GavaConnectSync
166
+
167
+ with GavaConnect(environment="sandbox") as gava:
168
+ record = gava.pin.check("A001234567Z")
169
+ print(f"Sync Identity Verified: {record.taxpayer_name}")
170
+
171
+ ```
172
+
173
+ ### Architectural Nuance: When to stay Synchronous (The Django Paradigm)
174
+
175
+ It is tempting to default to async for all network utilities, but context dictates performance. For example, if you are integrating this library into a traditional Django application served via a standard WSGI stack (like Gunicorn or uWSGI), you should choose the synchronous version.
176
+
177
+ The Technical Reason: Django’s core engine, request lifecycle middlewares, and database ORM layers are fundamentally synchronous by design. While Django offers async views, mixing them into a WSGI runtime forces the framework to wrap execution threads in thread-switching utility layers (`async_to_sync` and `sync_to_async`).
178
+
179
+ If your view is already handling a synchronous database transaction, throwing an asynchronous API call into the middle of it triggers complex context-switching overhead and thread hopping inside the Python runtime. This context switching can actually degrade performance and introduce subtle race conditions with thread-local data. Staying purely synchronous inside a synchronous application architecture keeps your execution path flat, memory overhead minimal, and debugging straightforward.
180
+
181
+ ---
182
+
183
+ # Path to Completeness (Module Roadmap)
184
+ The KRA API ecosystem is vast, covering everything from basic identity checks to complex customs calculations and tax filing routines. Rome wasn't built in a day, and neither is the ultimate developer gateway toolkit.
185
+
186
+ gava-connect-plus is a living blueprint. While the core verification bedrock is fully operational and production-ready, several advanced transactional modules are currently slated for future integration cycles.
187
+
188
+ Below is the current state of alignment between the SDK and the official developer.go.ke portal services:
189
+
190
+
191
+
192
+ <div align="center">
193
+
194
+ | Feature / API Endpoint | Status | Tested |
195
+ | --- | --- | :---: |
196
+ | Automated OAuth Token Lifecycle Management & Caching | ✅ | ✅ |
197
+ | PIN Checker by PIN (`PIN_Validation_by_PIN`) | ✅ | ✅ |
198
+ | PIN Checker by ID (`DTD_PINChecker`) | ✅ | ✅ |
199
+ | Know KRA Tax Service Office/Station (`SUC-iTax-USSD_Know_Your_Station`) | ✅ | ✅ |
200
+ | eTIMS Invoice Checker (`Invoice-Checker`) | ✅ | ✅ |
201
+ | Fetch Taxpayer Obligations (`TaxPayer_Tax_Obligations_Fetcher`) | ⏳ Planned | - |
202
+ | Withholding Tax PRN Generation (Income Tax, Rental, VAT) | ⏳ Planned | - |
203
+ | Tax Compliance Certificate (TCC) Validation & Application | ⏳ Planned | - |
204
+ | Automated NIL Return Filing (`iTax_NIL_Return`) | ⏳ Planned | - |
205
+ | Income Tax & VAT Exemption Checker | ⏳ Planned | - |
206
+ | Turnover Tax (TOT) Return Filing | ⏳ Planned | - |
207
+ | Customs Declaration Status Checker & Tax Calculator | ⏳ Planned | - |
208
+ | Import Certificate Checker (By Number / PIN) | ⏳ Planned | - |
209
+ | Individual KRA PIN Registration Gateway | ⏳ Planned | - |
210
+ | eTIMS OSCU Integrator Automated Testing Suite | ⏳ Planned | - |
211
+ | Excise License Checker (By Pin / Certificate Number) | ⏳ Planned | - |
212
+
213
+ </div>
214
+
215
+ # The Genesis & Contributing
216
+
217
+ Let’s clear the air right away: I am not affiliated, associated, authorized, or in any way officially connected with the Kenya Revenue Authority (KRA). This project was born out of pure, unadulterated developer frustration. While building a commercial product that required KRA portal integrations, I looked around the ecosystem for a robust, production-grade Python package that could handle the gateway safely and seamlessly. I found absolutely nothing.
218
+
219
+ Faced with a wall of fragmented PDFs and custom network scripts, I decided to take a deep breath, skip a few nights of sleep, and jump straight down the rabbit hole to build the tool that should have already existed. `gava-connect-plus` is the result of that journey.
220
+
221
+ ## Join the Journey
222
+ Because this is a community-driven initiative, your hands and minds are needed to help shape it. Whether you want to squash an edge-case bug, optimize the internal caching layers, or drag one of the *Planned transactional* modules into operational reality, contributions are deeply welcomed.
223
+
224
+ Feel free to open an issue, start a discussion thread, or send a pull request over the wall. Let's make integration painless for the next developer.
225
+
226
+ ## Support the energy
227
+ If gava-connect-plus saves you days of digging through portal specifications, keeps your production builds green, or spares your team a minor existential crisis, consider giving back to the project:
228
+ - **⭐ Star the Repository**: It costs nothing and directly helps other Kenyan developers discover the project on GitHub.
229
+ - **🗣️ Spread the Word**: Share the project link in your local tech WhatsApp groups, Discord servers, or on X (Twitter). Let's build a stronger local open-source culture.
230
+ - **☕ Buy Me a Coffee**: If this library saved your business real billable hours, consider fueling the midnight oil for the next sprint of module developments. Your support keeps the zen flowing.
231
+
232
+ <p align="center">
233
+ <picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/chart/github/stars/iammuuo/gava-connect-plus.svg?theme=green&amp;font=geist&amp;title=Github+stars+over+time&amp;icon=refinedgithub" /><img alt="chart" src="https://shieldcn.dev/chart/github/stars/iammuuo/gava-connect-plus.svg?mode=light&amp;theme=green&amp;font=geist&amp;title=Github+stars+over+time&amp;icon=refinedgithub" /></picture>
234
+ </p>
@@ -0,0 +1,36 @@
1
+ [project]
2
+ name = "gava-connect-plus"
3
+ version = "0.1.0"
4
+ description = "Async-first production-grade SDK for Kenya's GavaConnect Enterprise API platform."
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Erick", email = "hearteric57@gmail.com" }
8
+ ]
9
+ requires-python = ">=3.11"
10
+ dependencies = [
11
+ "blessed>=1.44.0",
12
+ "httpx>=0.28.1",
13
+ "pydantic>=2.13.4",
14
+ "pytest>=9.1.1",
15
+ "respx>=0.23.1",
16
+ ]
17
+
18
+ [build-system]
19
+ requires = ["uv_build>=0.11.23,<0.12.0"]
20
+ build-backend = "uv_build"
21
+
22
+
23
+ [tool.uv.build-backend]
24
+ module-name = "gavaconnect"
25
+
26
+ [dependency-groups]
27
+ dev = [
28
+ "pytest>=9.1.1",
29
+ "pytest-asyncio>=1.4.0",
30
+ "pytest-cov>=7.1.0",
31
+ "respx>=0.23.1",
32
+ ]
33
+
34
+ [project.scripts]
35
+ gava-connect = "gavaconnect.cli:main"
36
+ gava-tui = "gavaconnect.tui:run_tui"
@@ -0,0 +1,34 @@
1
+ from .async_client import GavaConnect
2
+ from .sync_client import GavaConnectSync
3
+
4
+ from .exceptions import (
5
+ GavaConnectError,
6
+ AuthenticationError,
7
+ InvoiceNotFoundError,
8
+ TransientError,
9
+ ValidationError,
10
+ APIError,
11
+ RateLimitError,
12
+ InvalidPINError,
13
+ InvalidTaxpayerIDError,
14
+ InvalidStationPINError,
15
+ )
16
+
17
+ __all__ = [
18
+ "GavaConnect",
19
+ "GavaConnectSync",
20
+ "GavaConnectError",
21
+ "AuthenticationError",
22
+ "InvoiceNotFoundError",
23
+ "TransientError",
24
+ "ValidationError",
25
+ "RateLimitError",
26
+ "APIError",
27
+ "InvalidTaxpayerIDError",
28
+ "InvalidPINError",
29
+ "InvalidStationPINError",
30
+ ]
31
+
32
+
33
+ def hello() -> str:
34
+ return "Hello from gava-connect-plus!"
@@ -0,0 +1,6 @@
1
+ from .pin import PinAPI, SyncPinAPI
2
+
3
+ __all__ = [
4
+ "PinAPI",
5
+ "SyncPinAPI",
6
+ ]