Skip to content

Commit 67cda10

Browse files
committed
Initial commit
0 parents  commit 67cda10

16 files changed

Lines changed: 810 additions & 0 deletions

.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
JENGA_API_KEY=
2+
JENGA_MERCHANT_CODE=
3+
JENGA_CONSUMER_SECRET=
4+
JENGA_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nreplace-with-private-key\n-----END PRIVATE KEY-----"
5+
JENGA_LIVE_MODE=false

.github/dependabot.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "pip"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
8+
- package-ecosystem: "github-actions"
9+
directory: "/"
10+
schedule:
11+
interval: "weekly"

.github/workflows/ci.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
paths-ignore:
6+
- "**/*.md"
7+
push:
8+
branches:
9+
- main
10+
paths-ignore:
11+
- "**/*.md"
12+
13+
jobs:
14+
test:
15+
runs-on: ubuntu-latest
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
python-version:
20+
- "3.10"
21+
- "3.11"
22+
- "3.12"
23+
24+
steps:
25+
- name: Check out repository
26+
uses: actions/checkout@v4
27+
28+
- name: Set up Python
29+
uses: actions/setup-python@v5
30+
with:
31+
python-version: ${{ matrix.python-version }}
32+
33+
- name: Install dependencies
34+
run: python -m pip install .
35+
36+
- name: Run tests
37+
run: python -m unittest discover -s tests

.gitignore

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
__pycache__/
2+
*.py[cod]
3+
4+
.env
5+
.venv/
6+
venv/
7+
8+
build/
9+
dist/
10+
*.egg-info/
11+
12+
.coverage
13+
.coverage.*
14+
.pytest_cache/
15+
.mypy_cache/
16+
htmlcov/
17+
.DS_Store
18+
.idea

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Njogu Amos
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.

README.md

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# jenga
2+
3+
A minimal Python package for interacting with selected Jenga API endpoints.
4+
5+
Implemented endpoints:
6+
7+
- `account-balance`
8+
- `mini-statement`
9+
10+
Implemented features:
11+
12+
- Reads configuration from environment variables
13+
- Generates access tokens
14+
- Signs request values with your RSA private key using `cryptography`
15+
- Provides both Python and CLI usage
16+
17+
Pending endpoints are listed later in this document.
18+
19+
## 1. Installation
20+
21+
```bash
22+
pip install jenga
23+
```
24+
25+
## 2. Configuration
26+
27+
The package reads configuration from environment variables. The required variables are:
28+
29+
```env
30+
JENGA_API_KEY=
31+
JENGA_MERCHANT_CODE=
32+
JENGA_CONSUMER_SECRET=
33+
JENGA_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nreplace-with-private-key\n-----END PRIVATE KEY-----"
34+
JENGA_LIVE_MODE=false
35+
```
36+
37+
> [!INFO]
38+
> - `JENGA_LIVE_MODE=true` uses `https://api.finserve.africa` white `JENGA_LIVE_MODE=false` uses `https://uat.finserve.africa`
39+
> - For PEM values, you can use either real multiline values or `\n`-escaped text in `.env` files.
40+
41+
If you are using a local `.env` file, load it into your shell before running commands:
42+
43+
## 3. Usage
44+
45+
### 3.1 Signature generation
46+
47+
Request signing is handled internally by `JengaClient` before protected endpoint calls are made.
48+
49+
If you need to generate a signature manually:
50+
51+
```python
52+
from jenga import JengaClient
53+
54+
client = JengaClient.from_env()
55+
signature = client.sign("KE", "1450160649886")
56+
```
57+
58+
The data is signed in the order it is passed.
59+
60+
### 3.1 Python usage
61+
62+
Use the package directly in your application code.
63+
64+
```python
65+
from jenga import JengaClient
66+
67+
client = JengaClient.from_env()
68+
69+
balance = client.account_balance(
70+
country_code="KE",
71+
account_id="1450160649886",
72+
)
73+
74+
statement = client.mini_statement(
75+
country_code="KE",
76+
account_id="1450160649886",
77+
)
78+
```
79+
80+
## 4. Endpoint Coverage
81+
82+
### 4.1 Account Services
83+
84+
<details>
85+
86+
<summary><strong>4.1.1 Account Balance</strong></summary>
87+
88+
Python:
89+
90+
```python
91+
from jenga import JengaClient
92+
93+
client = JengaClient.from_env()
94+
result = client.account_balance(country_code="KE", account_id="1450160649886")
95+
print(result)
96+
```
97+
98+
CLI:
99+
100+
```bash
101+
PYTHONPATH=src python3 -m jenga.cli account-balance --country-code KE --account-id 1450160649886
102+
```
103+
104+
</details>
105+
106+
<details>
107+
108+
<summary><strong>4.1.2 Account Mini Statement</strong></summary>
109+
110+
Python:
111+
112+
```python
113+
from jenga import JengaClient
114+
115+
client = JengaClient.from_env()
116+
result = client.mini_statement(country_code="KE", account_id="1450160649886")
117+
print(result)
118+
```
119+
120+
CLI:
121+
122+
```bash
123+
PYTHONPATH=src python3 -m jenga.cli mini-statement --country-code KE --account-id 1450160649886
124+
```
125+
126+
</details>
127+
128+
- [ ] Account Full Statement
129+
- [ ] Opening and Closing Account Balance
130+
- [ ] Account Inquiry - Bank Accounts
131+
132+
### 4.2 Send Money
133+
134+
- [ ] Within Equity Bank
135+
- [ ] To Mobile Wallets
136+
- [ ] RTGS
137+
- [ ] SWIFT
138+
- [ ] Pesalink - To Bank Account
139+
- [ ] Pesalink - To Mobile Number
140+
141+
### 4.3 Send Money - IMT
142+
143+
- [ ] IMT Within Equity Bank
144+
- [ ] IMT to Mobile Wallets
145+
- [ ] IMT Pesalink - To Bank Account
146+
- [ ] IMT Pesalink - To Bank Mobile
147+
148+
### 4.4 Receive Money
149+
150+
- [ ] Receive Payments - Bill Payments
151+
- [ ] Receive Payments - Merchant Payments
152+
- [ ] Bill Validation
153+
154+
### 4.5 Receive Money Queries
155+
156+
- [ ] Get All EazzyPay Merchants
157+
- [ ] Query Transaction Details
158+
- [ ] Get All Billers
159+
160+
### 4.6 Airtime
161+
162+
- [ ] Purchase Airtime
163+
164+
### 4.7 Forex Rates
165+
166+
- [ ] Forex Exchange Rates
167+
168+
### 4.8 ID Search and Verification
169+
170+
- [ ] ID Search and Verification
171+
172+
### 4.9 MPGS Direct Integration
173+
174+
- [ ] MPGS Validate Payment
175+
- [ ] MPGS Authenticate Payment
176+
- [ ] MPGS Authorize Payment
177+
- [ ] MPGS Query Payment
178+
- [ ] MPGS Refund Payment
179+
180+
## 5. Testing
181+
182+
Run the automated tests:
183+
184+
```bash
185+
python3 -m unittest discover -s tests
186+
```
187+
188+
Run a real manual test with your local `.env`:
189+
190+
```bash
191+
set -a
192+
source .env
193+
set +a
194+
PYTHONPATH=src python3 -m jenga.cli account-balance --country-code KE --account-id 1450160649886
195+
```
196+
197+
## 6. Notes
198+
199+
- This package currently focuses on a small subset of Jenga APIs.
200+
- The README only documents endpoints that are actually implemented in this repository.
201+
- Pending endpoints are listed for roadmap visibility only.
202+
203+
## 7. License
204+
License: [MIT](./LICENSE)

licence.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Njogu amos
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.

pyproject.toml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
[build-system]
2+
requires = ["setuptools>=68"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "jenga"
7+
version = "0.1.0"
8+
description = "Minimal Python client for selected Jenga APIs"
9+
license = { text = "MIT" }
10+
readme = "README.md"
11+
requires-python = ">=3.10"
12+
authors = [
13+
{name = "Njogu Amos", email = "njoguamos@gmail.com"},
14+
]
15+
dependencies = [
16+
"cryptography>=42",
17+
]
18+
19+
[project.optional-dependencies]
20+
dev = []
21+
22+
[project.scripts]
23+
jenga = "jenga.cli:main"
24+
25+
[project.urls]
26+
Homepage = "https://github.com/paymentsdks/jenga-python"
27+
Issues = "https://github.com/paymentsdks/jenga-python/issues"
28+
29+
[tool.setuptools]
30+
package-dir = {"" = "src"}
31+
32+
[tool.setuptools.packages.find]
33+
where = ["src"]

src/jenga/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from .client import JengaClient
2+
from .config import JengaConfig
3+
from .exceptions import JengaConfigError, JengaError, JengaRequestError, JengaSignatureError
4+
5+
__all__ = [
6+
"JengaClient",
7+
"JengaConfig",
8+
"JengaConfigError",
9+
"JengaError",
10+
"JengaRequestError",
11+
"JengaSignatureError",
12+
]

0 commit comments

Comments
 (0)