chamapay 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,97 @@
1
+ Metadata-Version: 2.4
2
+ Name: chamapay
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for ChamaPay API — Financial Infrastructure for African Savings Groups
5
+ Author-email: ChamaPay <api-support@chamapay.co.ke>
6
+ License: MIT
7
+ Project-URL: Homepage, https://chamapay.co.ke
8
+ Project-URL: Documentation, https://api.chamapay.co.ke/docs
9
+ Project-URL: Source, https://github.com/chamapay/chamapay-python
10
+ Keywords: chamapay,sacco,savings,mpesa,africa,fintech
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Requires-Python: >=3.8
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: requests>=2.25.0
23
+
24
+ # ChamaPay Python SDK
25
+
26
+ Official Python SDK for the ChamaPay API.
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ pip install chamapay
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ ```python
37
+ from chamapay import ChamaPay
38
+
39
+ api = ChamaPay('cpk_live_your_api_key', 'your_api_secret')
40
+
41
+ # List members
42
+ members = api.members.list(status='Active', page=1, limit=20)
43
+
44
+ # Create a contribution (idempotent)
45
+ contribution = api.contributions.create(
46
+ {'member_id': 'MFT001', 'amount': 5000},
47
+ idempotency_key='550e8400-e29b-41d4-a716-446655440000'
48
+ )
49
+
50
+ # Get loan details
51
+ loan = api.loans.get('LN001')
52
+ ```
53
+
54
+ ## API Reference
55
+
56
+ | Resource | Methods |
57
+ |--------------------|--------------------------------------------|
58
+ | members | list, get, create, update, delete |
59
+ | contributions | list, get, create (with idempotency key) |
60
+ | loans | list, get, create |
61
+ | fines | list, create |
62
+ | meetings | list, create |
63
+ | projects | list, create |
64
+ | accounts | list, get |
65
+ | welfare | list |
66
+ | dividends | list |
67
+ | documents | list |
68
+ | election_notices | list |
69
+ | document_reminders | list |
70
+ | audit | list |
71
+ | liabilities | list, create |
72
+ | reports | get |
73
+
74
+ ## Error Handling
75
+
76
+ ```python
77
+ from chamapay import ChamaPayError, ValidationError, RateLimitError
78
+
79
+ try:
80
+ api.members.create({...})
81
+ except ValidationError as e:
82
+ print(f"Validation failed: {e.details}")
83
+ except RateLimitError as e:
84
+ print(f"Rate limited. Retry after {e.retry_after}s")
85
+ except ChamaPayError as e:
86
+ print(f"API Error [{e.code}]: {e.message}")
87
+ ```
88
+
89
+ ## Publishing
90
+
91
+ ```bash
92
+ pip install build twine
93
+ python -m build
94
+ twine upload dist/*
95
+ ```
96
+
97
+ Requires a PyPI account with access to the `chamapay` package.
@@ -0,0 +1,74 @@
1
+ # ChamaPay Python SDK
2
+
3
+ Official Python SDK for the ChamaPay API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install chamapay
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```python
14
+ from chamapay import ChamaPay
15
+
16
+ api = ChamaPay('cpk_live_your_api_key', 'your_api_secret')
17
+
18
+ # List members
19
+ members = api.members.list(status='Active', page=1, limit=20)
20
+
21
+ # Create a contribution (idempotent)
22
+ contribution = api.contributions.create(
23
+ {'member_id': 'MFT001', 'amount': 5000},
24
+ idempotency_key='550e8400-e29b-41d4-a716-446655440000'
25
+ )
26
+
27
+ # Get loan details
28
+ loan = api.loans.get('LN001')
29
+ ```
30
+
31
+ ## API Reference
32
+
33
+ | Resource | Methods |
34
+ |--------------------|--------------------------------------------|
35
+ | members | list, get, create, update, delete |
36
+ | contributions | list, get, create (with idempotency key) |
37
+ | loans | list, get, create |
38
+ | fines | list, create |
39
+ | meetings | list, create |
40
+ | projects | list, create |
41
+ | accounts | list, get |
42
+ | welfare | list |
43
+ | dividends | list |
44
+ | documents | list |
45
+ | election_notices | list |
46
+ | document_reminders | list |
47
+ | audit | list |
48
+ | liabilities | list, create |
49
+ | reports | get |
50
+
51
+ ## Error Handling
52
+
53
+ ```python
54
+ from chamapay import ChamaPayError, ValidationError, RateLimitError
55
+
56
+ try:
57
+ api.members.create({...})
58
+ except ValidationError as e:
59
+ print(f"Validation failed: {e.details}")
60
+ except RateLimitError as e:
61
+ print(f"Rate limited. Retry after {e.retry_after}s")
62
+ except ChamaPayError as e:
63
+ print(f"API Error [{e.code}]: {e.message}")
64
+ ```
65
+
66
+ ## Publishing
67
+
68
+ ```bash
69
+ pip install build twine
70
+ python -m build
71
+ twine upload dist/*
72
+ ```
73
+
74
+ Requires a PyPI account with access to the `chamapay` package.
@@ -0,0 +1,12 @@
1
+ from .client import ChamaPay
2
+ from .errors import ChamaPayError, AuthenticationError, RateLimitError, ValidationError, NotFoundError, ServerError
3
+
4
+ __all__ = [
5
+ "ChamaPay",
6
+ "ChamaPayError",
7
+ "AuthenticationError",
8
+ "RateLimitError",
9
+ "ValidationError",
10
+ "NotFoundError",
11
+ "ServerError",
12
+ ]
@@ -0,0 +1,36 @@
1
+ from .http_client import ChamaPayClient
2
+ from .resources.members import MembersResource
3
+ from .resources.contributions import ContributionsResource
4
+ from .resources.loans import LoansResource
5
+ from .resources.fines import FinesResource
6
+ from .resources.meetings import MeetingsResource
7
+ from .resources.projects import ProjectsResource
8
+ from .resources.accounts import AccountsResource
9
+ from .resources.welfare import WelfareResource
10
+ from .resources.dividends import DividendsResource
11
+ from .resources.documents import DocumentsResource
12
+ from .resources.election_notices import ElectionNoticesResource
13
+ from .resources.document_reminders import DocumentRemindersResource
14
+ from .resources.audit import AuditResource
15
+ from .resources.liabilities import LiabilitiesResource
16
+ from .resources.reports import ReportsResource
17
+
18
+
19
+ class ChamaPay:
20
+ def __init__(self, api_key, api_secret, base_url=None, timeout=None):
21
+ client = ChamaPayClient(api_key, api_secret, base_url, timeout)
22
+ self.members = MembersResource(client)
23
+ self.contributions = ContributionsResource(client)
24
+ self.loans = LoansResource(client)
25
+ self.fines = FinesResource(client)
26
+ self.meetings = MeetingsResource(client)
27
+ self.projects = ProjectsResource(client)
28
+ self.accounts = AccountsResource(client)
29
+ self.welfare = WelfareResource(client)
30
+ self.dividends = DividendsResource(client)
31
+ self.documents = DocumentsResource(client)
32
+ self.election_notices = ElectionNoticesResource(client)
33
+ self.document_reminders = DocumentRemindersResource(client)
34
+ self.audit = AuditResource(client)
35
+ self.liabilities = LiabilitiesResource(client)
36
+ self.reports = ReportsResource(client)
@@ -0,0 +1,27 @@
1
+ class ChamaPayError(Exception):
2
+ def __init__(self, message, status=0, code=None, details=None):
3
+ super().__init__(message)
4
+ self.status = status
5
+ self.code = code
6
+ self.details = details or {}
7
+
8
+ class AuthenticationError(ChamaPayError):
9
+ def __init__(self, message, details=None):
10
+ super().__init__(message, 401, "authentication_error", details)
11
+
12
+ class RateLimitError(ChamaPayError):
13
+ def __init__(self, message, retry_after=30, details=None):
14
+ super().__init__(message, 429, "rate_limit_error", details)
15
+ self.retry_after = retry_after
16
+
17
+ class ValidationError(ChamaPayError):
18
+ def __init__(self, message, details=None):
19
+ super().__init__(message, 422, "validation_error", details)
20
+
21
+ class NotFoundError(ChamaPayError):
22
+ def __init__(self, message, details=None):
23
+ super().__init__(message, 404, "not_found", details)
24
+
25
+ class ServerError(ChamaPayError):
26
+ def __init__(self, message, details=None):
27
+ super().__init__(message, 500, "server_error", details)
@@ -0,0 +1,85 @@
1
+ import requests
2
+
3
+ from .errors import (
4
+ ChamaPayError,
5
+ AuthenticationError,
6
+ RateLimitError,
7
+ ValidationError,
8
+ NotFoundError,
9
+ ServerError,
10
+ )
11
+
12
+ BASE_URL = "https://api.chamapay.co.ke/v1"
13
+ DEFAULT_TIMEOUT = 30
14
+
15
+ _ERROR_MAP = {
16
+ 401: AuthenticationError,
17
+ 404: NotFoundError,
18
+ 422: ValidationError,
19
+ 429: RateLimitError,
20
+ 500: ServerError,
21
+ }
22
+
23
+
24
+ class ChamaPayClient:
25
+ def __init__(self, api_key, api_secret, base_url=None, timeout=None):
26
+ if not api_key or not api_secret:
27
+ raise ChamaPayError("API key and secret are required")
28
+ self.api_key = api_key
29
+ self.api_secret = api_secret
30
+ self.base_url = (base_url or BASE_URL).rstrip("/")
31
+ self.timeout = timeout or DEFAULT_TIMEOUT
32
+ self._session = requests.Session()
33
+ self._session.headers.update({
34
+ "Authorization": f"Bearer {self.api_key}:{self.api_secret}",
35
+ "Content-Type": "application/json",
36
+ "User-Agent": "chamapay-python/1.0.0",
37
+ })
38
+
39
+ def _request(self, method, path, **kwargs):
40
+ url = f"{self.base_url}/{path.lstrip('/')}"
41
+ params = kwargs.get("query")
42
+ body = kwargs.get("body")
43
+ extra_headers = kwargs.get("headers", {})
44
+
45
+ try:
46
+ res = self._session.request(
47
+ method=method,
48
+ url=url,
49
+ params=params,
50
+ json=body,
51
+ headers=extra_headers or None,
52
+ timeout=self.timeout,
53
+ )
54
+ except requests.exceptions.Timeout:
55
+ raise ChamaPayError("Request timed out", 0, "timeout")
56
+ except requests.exceptions.ConnectionError as e:
57
+ raise ChamaPayError(f"Connection error: {e}", 0, "connection_error")
58
+
59
+ try:
60
+ data = res.json()
61
+ except ValueError:
62
+ data = {"error": {"message": res.text}}
63
+
64
+ if not res.ok:
65
+ err = data.get("error", data)
66
+ msg = err.get("message", f"Request failed with status {res.status_code}")
67
+ err_cls = _ERROR_MAP.get(res.status_code, ChamaPayError)
68
+ raise err_cls(msg, err.get("details"))
69
+
70
+ return data
71
+
72
+ def get(self, path, **opts):
73
+ return self._request("GET", path, **opts)
74
+
75
+ def post(self, path, **opts):
76
+ return self._request("POST", path, **opts)
77
+
78
+ def put(self, path, **opts):
79
+ return self._request("PUT", path, **opts)
80
+
81
+ def patch(self, path, **opts):
82
+ return self._request("PATCH", path, **opts)
83
+
84
+ def delete(self, path, **opts):
85
+ return self._request("DELETE", path, **opts)
@@ -0,0 +1,33 @@
1
+ from .members import MembersResource
2
+ from .contributions import ContributionsResource
3
+ from .loans import LoansResource
4
+ from .fines import FinesResource
5
+ from .meetings import MeetingsResource
6
+ from .projects import ProjectsResource
7
+ from .accounts import AccountsResource
8
+ from .welfare import WelfareResource
9
+ from .dividends import DividendsResource
10
+ from .documents import DocumentsResource
11
+ from .election_notices import ElectionNoticesResource
12
+ from .document_reminders import DocumentRemindersResource
13
+ from .audit import AuditResource
14
+ from .liabilities import LiabilitiesResource
15
+ from .reports import ReportsResource
16
+
17
+ __all__ = [
18
+ "MembersResource",
19
+ "ContributionsResource",
20
+ "LoansResource",
21
+ "FinesResource",
22
+ "MeetingsResource",
23
+ "ProjectsResource",
24
+ "AccountsResource",
25
+ "WelfareResource",
26
+ "DividendsResource",
27
+ "DocumentsResource",
28
+ "ElectionNoticesResource",
29
+ "DocumentRemindersResource",
30
+ "AuditResource",
31
+ "LiabilitiesResource",
32
+ "ReportsResource",
33
+ ]
@@ -0,0 +1,4 @@
1
+ class AccountsResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/accounts", query=q)
4
+ def get(self, id): return self._c.get(f"/accounts/{id}")
@@ -0,0 +1,3 @@
1
+ class AuditResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/audit", query=q)
@@ -0,0 +1,7 @@
1
+ class ContributionsResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/contributions", query=q)
4
+ def get(self, id): return self._c.get(f"/contributions/{id}")
5
+ def create(self, body, idempotency_key=None):
6
+ h = {"Idempotency-Key": idempotency_key} if idempotency_key else {}
7
+ return self._c.post("/contributions", body=body, headers=h)
@@ -0,0 +1,3 @@
1
+ class DividendsResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/dividends", query=q)
@@ -0,0 +1,3 @@
1
+ class DocumentRemindersResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/document_reminders", query=q)
@@ -0,0 +1,3 @@
1
+ class DocumentsResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/documents", query=q)
@@ -0,0 +1,3 @@
1
+ class ElectionNoticesResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/election_notices", query=q)
@@ -0,0 +1,4 @@
1
+ class FinesResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/fines", query=q)
4
+ def create(self, **b): return self._c.post("/fines", body=b)
@@ -0,0 +1,4 @@
1
+ class LiabilitiesResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/liabilities", query=q)
4
+ def create(self, **b): return self._c.post("/liabilities", body=b)
@@ -0,0 +1,5 @@
1
+ class LoansResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/loans", query=q)
4
+ def get(self, id): return self._c.get(f"/loans/{id}")
5
+ def create(self, **b): return self._c.post("/loans", body=b)
@@ -0,0 +1,4 @@
1
+ class MeetingsResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/meetings", query=q)
4
+ def create(self, **b): return self._c.post("/meetings", body=b)
@@ -0,0 +1,7 @@
1
+ class MembersResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/members", query=q)
4
+ def get(self, id): return self._c.get(f"/members/{id}")
5
+ def create(self, **b): return self._c.post("/members", body=b)
6
+ def update(self, id, **b): return self._c.put(f"/members/{id}", body=b)
7
+ def delete(self, id): return self._c.delete(f"/members/{id}")
@@ -0,0 +1,4 @@
1
+ class ProjectsResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/projects", query=q)
4
+ def create(self, **b): return self._c.post("/projects", body=b)
@@ -0,0 +1,3 @@
1
+ class ReportsResource:
2
+ def __init__(self, client): self._c = client
3
+ def get(self, **q): return self._c.get("/reports", query=q)
@@ -0,0 +1,3 @@
1
+ class WelfareResource:
2
+ def __init__(self, client): self._c = client
3
+ def list(self, **q): return self._c.get("/welfare", query=q)
@@ -0,0 +1,97 @@
1
+ Metadata-Version: 2.4
2
+ Name: chamapay
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for ChamaPay API — Financial Infrastructure for African Savings Groups
5
+ Author-email: ChamaPay <api-support@chamapay.co.ke>
6
+ License: MIT
7
+ Project-URL: Homepage, https://chamapay.co.ke
8
+ Project-URL: Documentation, https://api.chamapay.co.ke/docs
9
+ Project-URL: Source, https://github.com/chamapay/chamapay-python
10
+ Keywords: chamapay,sacco,savings,mpesa,africa,fintech
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Requires-Python: >=3.8
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: requests>=2.25.0
23
+
24
+ # ChamaPay Python SDK
25
+
26
+ Official Python SDK for the ChamaPay API.
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ pip install chamapay
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ ```python
37
+ from chamapay import ChamaPay
38
+
39
+ api = ChamaPay('cpk_live_your_api_key', 'your_api_secret')
40
+
41
+ # List members
42
+ members = api.members.list(status='Active', page=1, limit=20)
43
+
44
+ # Create a contribution (idempotent)
45
+ contribution = api.contributions.create(
46
+ {'member_id': 'MFT001', 'amount': 5000},
47
+ idempotency_key='550e8400-e29b-41d4-a716-446655440000'
48
+ )
49
+
50
+ # Get loan details
51
+ loan = api.loans.get('LN001')
52
+ ```
53
+
54
+ ## API Reference
55
+
56
+ | Resource | Methods |
57
+ |--------------------|--------------------------------------------|
58
+ | members | list, get, create, update, delete |
59
+ | contributions | list, get, create (with idempotency key) |
60
+ | loans | list, get, create |
61
+ | fines | list, create |
62
+ | meetings | list, create |
63
+ | projects | list, create |
64
+ | accounts | list, get |
65
+ | welfare | list |
66
+ | dividends | list |
67
+ | documents | list |
68
+ | election_notices | list |
69
+ | document_reminders | list |
70
+ | audit | list |
71
+ | liabilities | list, create |
72
+ | reports | get |
73
+
74
+ ## Error Handling
75
+
76
+ ```python
77
+ from chamapay import ChamaPayError, ValidationError, RateLimitError
78
+
79
+ try:
80
+ api.members.create({...})
81
+ except ValidationError as e:
82
+ print(f"Validation failed: {e.details}")
83
+ except RateLimitError as e:
84
+ print(f"Rate limited. Retry after {e.retry_after}s")
85
+ except ChamaPayError as e:
86
+ print(f"API Error [{e.code}]: {e.message}")
87
+ ```
88
+
89
+ ## Publishing
90
+
91
+ ```bash
92
+ pip install build twine
93
+ python -m build
94
+ twine upload dist/*
95
+ ```
96
+
97
+ Requires a PyPI account with access to the `chamapay` package.
@@ -0,0 +1,27 @@
1
+ README.md
2
+ pyproject.toml
3
+ chamapay/__init__.py
4
+ chamapay/client.py
5
+ chamapay/errors.py
6
+ chamapay/http_client.py
7
+ chamapay.egg-info/PKG-INFO
8
+ chamapay.egg-info/SOURCES.txt
9
+ chamapay.egg-info/dependency_links.txt
10
+ chamapay.egg-info/requires.txt
11
+ chamapay.egg-info/top_level.txt
12
+ chamapay/resources/__init__.py
13
+ chamapay/resources/accounts.py
14
+ chamapay/resources/audit.py
15
+ chamapay/resources/contributions.py
16
+ chamapay/resources/dividends.py
17
+ chamapay/resources/document_reminders.py
18
+ chamapay/resources/documents.py
19
+ chamapay/resources/election_notices.py
20
+ chamapay/resources/fines.py
21
+ chamapay/resources/liabilities.py
22
+ chamapay/resources/loans.py
23
+ chamapay/resources/meetings.py
24
+ chamapay/resources/members.py
25
+ chamapay/resources/projects.py
26
+ chamapay/resources/reports.py
27
+ chamapay/resources/welfare.py
@@ -0,0 +1 @@
1
+ requests>=2.25.0
@@ -0,0 +1 @@
1
+ chamapay
@@ -0,0 +1,34 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "chamapay"
7
+ version = "1.0.0"
8
+ description = "Official Python SDK for ChamaPay API — Financial Infrastructure for African Savings Groups"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ {name = "ChamaPay", email = "api-support@chamapay.co.ke"}
14
+ ]
15
+ keywords = ["chamapay", "sacco", "savings", "mpesa", "africa", "fintech"]
16
+ classifiers = [
17
+ "Development Status :: 5 - Production/Stable",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.8",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ ]
27
+ dependencies = [
28
+ "requests>=2.25.0",
29
+ ]
30
+
31
+ [project.urls]
32
+ Homepage = "https://chamapay.co.ke"
33
+ Documentation = "https://api.chamapay.co.ke/docs"
34
+ Source = "https://github.com/chamapay/chamapay-python"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+