mansaapi 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.
- mansaapi-0.1.0/.gitignore +9 -0
- mansaapi-0.1.0/LICENSE +21 -0
- mansaapi-0.1.0/PKG-INFO +146 -0
- mansaapi-0.1.0/README.md +131 -0
- mansaapi-0.1.0/pyproject.toml +22 -0
- mansaapi-0.1.0/src/mansaapi/__init__.py +4 -0
- mansaapi-0.1.0/src/mansaapi/_client.py +217 -0
- mansaapi-0.1.0/src/mansaapi/errors.py +17 -0
mansaapi-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mansa Labs
|
|
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.
|
mansaapi-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mansaapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for Mansa API — African market data, bank codes, location, and identity.
|
|
5
|
+
Project-URL: Homepage, https://mansaapi.com
|
|
6
|
+
Project-URL: Documentation, https://mansaapi.com/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/HeyZod/mansaapi-python
|
|
8
|
+
Author: Mansa Labs
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: africa,african,api,bank codes,fintech,ngx,nigeria,sdk,stock market
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
|
+
Requires-Dist: requests>=2.25
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# mansaapi (Python)
|
|
17
|
+
|
|
18
|
+
Official Python SDK for [Mansa API](https://mansaapi.com) — African market data, bank codes, location, and financial identity in one clean REST layer.
|
|
19
|
+
|
|
20
|
+
[](https://pypi.org/project/mansaapi/)
|
|
21
|
+
[](LICENSE)
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install mansaapi
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from mansaapi import MansaAPI
|
|
33
|
+
|
|
34
|
+
mansa = MansaAPI(api_key="mansa_live_sk_...")
|
|
35
|
+
|
|
36
|
+
# GTBank by code
|
|
37
|
+
bank = mansa.identity.get_bank("058")
|
|
38
|
+
print(bank["data"]["name"]) # "Guaranty Trust Bank (GTBank)"
|
|
39
|
+
print(bank["data"]["swift_code"]) # "GTBINGLA"
|
|
40
|
+
|
|
41
|
+
# Pan-African market movers
|
|
42
|
+
movers = mansa.markets.get_pan_african_movers(limit=10)
|
|
43
|
+
|
|
44
|
+
# Nigerian public holidays 2026
|
|
45
|
+
holidays = mansa.location.get_holidays("NG", 2026)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Get a free API key at [mansaapi.com](https://mansaapi.com) — 100 requests/day, no credit card.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Markets
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
mansa.markets.get_exchanges()
|
|
56
|
+
mansa.markets.get_stocks("NGX", sector="Banking", limit=20)
|
|
57
|
+
mansa.markets.get_stock("NGX", "GTCO")
|
|
58
|
+
mansa.markets.get_movers("NGX", type="gainers")
|
|
59
|
+
mansa.markets.get_pan_african_movers()
|
|
60
|
+
mansa.markets.get_indices("NGX")
|
|
61
|
+
mansa.markets.get_etfs("NGX")
|
|
62
|
+
mansa.markets.get_forex()
|
|
63
|
+
mansa.markets.get_commodities()
|
|
64
|
+
mansa.markets.search("Zenith", exchange="NGX")
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Premium endpoints
|
|
68
|
+
|
|
69
|
+
Starter tier or higher for dividends, disclosures, recommendations.
|
|
70
|
+
Pro tier for insider trades. See [mansaapi.com/pricing](https://mansaapi.com/pricing).
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
mansa.markets.get_dividends("NGX", "GTCO") # Starter+
|
|
74
|
+
mansa.markets.get_disclosures("NGX", symbol="GTCO") # Starter+
|
|
75
|
+
mansa.markets.get_recommendations("NGX") # Starter+
|
|
76
|
+
mansa.markets.get_insider_trades("NGX", days=30) # Pro+
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Identity
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
mansa.identity.get_banks() # all African banks
|
|
85
|
+
mansa.identity.get_banks(country="NG") # filter by country
|
|
86
|
+
mansa.identity.get_bank("057") # single bank by code
|
|
87
|
+
mansa.identity.get_mobile_networks(country="GH")
|
|
88
|
+
mansa.identity.lookup_mobile_network("08031234567")
|
|
89
|
+
mansa.identity.get_currencies()
|
|
90
|
+
mansa.identity.validate_nuban("0123456789", "058")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Location
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
mansa.location.get_countries()
|
|
99
|
+
mansa.location.get_country("NG")
|
|
100
|
+
mansa.location.get_states("NG")
|
|
101
|
+
mansa.location.get_lgas("NG", "LA") # Lagos LGAs
|
|
102
|
+
mansa.location.get_holidays("NG", 2026)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Error handling
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from mansaapi import MansaAPI, MansaAPIError
|
|
111
|
+
|
|
112
|
+
mansa = MansaAPI(api_key="mansa_live_sk_...")
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
data = mansa.markets.get_insider_trades("NGX")
|
|
116
|
+
except MansaAPIError as err:
|
|
117
|
+
print(err.code) # "TIER_REQUIRED"
|
|
118
|
+
print(err.status) # 403
|
|
119
|
+
print(err.message) # "This endpoint requires a professional tier key..."
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Error codes
|
|
123
|
+
|
|
124
|
+
| Code | Status | Meaning |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| `INVALID_API_KEY` | 401 | Key not found or revoked |
|
|
127
|
+
| `RATE_LIMIT_EXCEEDED` | 429 | Daily request limit reached |
|
|
128
|
+
| `TIER_REQUIRED` | 403 | Endpoint requires a higher tier |
|
|
129
|
+
| `NOT_FOUND` | 404 | Resource not found |
|
|
130
|
+
| `UPSTREAM_ERROR` | 502 | Upstream data source unreachable |
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Supported exchanges
|
|
135
|
+
|
|
136
|
+
NGX (Nigeria), GSE (Ghana), NSE (Kenya), JSE (South Africa), BRVM (West Africa), DSE (Tanzania), LUSE (Zambia).
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Links
|
|
141
|
+
|
|
142
|
+
- [Documentation](https://mansaapi.com/docs)
|
|
143
|
+
- [Python quickstart](https://mansaapi.com/docs/quickstart/python)
|
|
144
|
+
- [Pricing](https://mansaapi.com/pricing)
|
|
145
|
+
- [OpenAPI spec](https://mansaapi.com/openapi.json)
|
|
146
|
+
- [api@mansamarkets.com](mailto:api@mansamarkets.com)
|
mansaapi-0.1.0/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# mansaapi (Python)
|
|
2
|
+
|
|
3
|
+
Official Python SDK for [Mansa API](https://mansaapi.com) — African market data, bank codes, location, and financial identity in one clean REST layer.
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/mansaapi/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install mansaapi
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick start
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from mansaapi import MansaAPI
|
|
18
|
+
|
|
19
|
+
mansa = MansaAPI(api_key="mansa_live_sk_...")
|
|
20
|
+
|
|
21
|
+
# GTBank by code
|
|
22
|
+
bank = mansa.identity.get_bank("058")
|
|
23
|
+
print(bank["data"]["name"]) # "Guaranty Trust Bank (GTBank)"
|
|
24
|
+
print(bank["data"]["swift_code"]) # "GTBINGLA"
|
|
25
|
+
|
|
26
|
+
# Pan-African market movers
|
|
27
|
+
movers = mansa.markets.get_pan_african_movers(limit=10)
|
|
28
|
+
|
|
29
|
+
# Nigerian public holidays 2026
|
|
30
|
+
holidays = mansa.location.get_holidays("NG", 2026)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Get a free API key at [mansaapi.com](https://mansaapi.com) — 100 requests/day, no credit card.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Markets
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
mansa.markets.get_exchanges()
|
|
41
|
+
mansa.markets.get_stocks("NGX", sector="Banking", limit=20)
|
|
42
|
+
mansa.markets.get_stock("NGX", "GTCO")
|
|
43
|
+
mansa.markets.get_movers("NGX", type="gainers")
|
|
44
|
+
mansa.markets.get_pan_african_movers()
|
|
45
|
+
mansa.markets.get_indices("NGX")
|
|
46
|
+
mansa.markets.get_etfs("NGX")
|
|
47
|
+
mansa.markets.get_forex()
|
|
48
|
+
mansa.markets.get_commodities()
|
|
49
|
+
mansa.markets.search("Zenith", exchange="NGX")
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Premium endpoints
|
|
53
|
+
|
|
54
|
+
Starter tier or higher for dividends, disclosures, recommendations.
|
|
55
|
+
Pro tier for insider trades. See [mansaapi.com/pricing](https://mansaapi.com/pricing).
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
mansa.markets.get_dividends("NGX", "GTCO") # Starter+
|
|
59
|
+
mansa.markets.get_disclosures("NGX", symbol="GTCO") # Starter+
|
|
60
|
+
mansa.markets.get_recommendations("NGX") # Starter+
|
|
61
|
+
mansa.markets.get_insider_trades("NGX", days=30) # Pro+
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Identity
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
mansa.identity.get_banks() # all African banks
|
|
70
|
+
mansa.identity.get_banks(country="NG") # filter by country
|
|
71
|
+
mansa.identity.get_bank("057") # single bank by code
|
|
72
|
+
mansa.identity.get_mobile_networks(country="GH")
|
|
73
|
+
mansa.identity.lookup_mobile_network("08031234567")
|
|
74
|
+
mansa.identity.get_currencies()
|
|
75
|
+
mansa.identity.validate_nuban("0123456789", "058")
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Location
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
mansa.location.get_countries()
|
|
84
|
+
mansa.location.get_country("NG")
|
|
85
|
+
mansa.location.get_states("NG")
|
|
86
|
+
mansa.location.get_lgas("NG", "LA") # Lagos LGAs
|
|
87
|
+
mansa.location.get_holidays("NG", 2026)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Error handling
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from mansaapi import MansaAPI, MansaAPIError
|
|
96
|
+
|
|
97
|
+
mansa = MansaAPI(api_key="mansa_live_sk_...")
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
data = mansa.markets.get_insider_trades("NGX")
|
|
101
|
+
except MansaAPIError as err:
|
|
102
|
+
print(err.code) # "TIER_REQUIRED"
|
|
103
|
+
print(err.status) # 403
|
|
104
|
+
print(err.message) # "This endpoint requires a professional tier key..."
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Error codes
|
|
108
|
+
|
|
109
|
+
| Code | Status | Meaning |
|
|
110
|
+
|---|---|---|
|
|
111
|
+
| `INVALID_API_KEY` | 401 | Key not found or revoked |
|
|
112
|
+
| `RATE_LIMIT_EXCEEDED` | 429 | Daily request limit reached |
|
|
113
|
+
| `TIER_REQUIRED` | 403 | Endpoint requires a higher tier |
|
|
114
|
+
| `NOT_FOUND` | 404 | Resource not found |
|
|
115
|
+
| `UPSTREAM_ERROR` | 502 | Upstream data source unreachable |
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Supported exchanges
|
|
120
|
+
|
|
121
|
+
NGX (Nigeria), GSE (Ghana), NSE (Kenya), JSE (South Africa), BRVM (West Africa), DSE (Tanzania), LUSE (Zambia).
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Links
|
|
126
|
+
|
|
127
|
+
- [Documentation](https://mansaapi.com/docs)
|
|
128
|
+
- [Python quickstart](https://mansaapi.com/docs/quickstart/python)
|
|
129
|
+
- [Pricing](https://mansaapi.com/pricing)
|
|
130
|
+
- [OpenAPI spec](https://mansaapi.com/openapi.json)
|
|
131
|
+
- [api@mansamarkets.com](mailto:api@mansamarkets.com)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mansaapi"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Official Python SDK for Mansa API — African market data, bank codes, location, and identity."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
authors = [{ name = "Mansa Labs" }]
|
|
12
|
+
requires-python = ">=3.8"
|
|
13
|
+
keywords = ["africa", "african", "stock market", "bank codes", "nigeria", "ngx", "fintech", "api", "sdk"]
|
|
14
|
+
dependencies = ["requests>=2.25"]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Homepage = "https://mansaapi.com"
|
|
18
|
+
Documentation = "https://mansaapi.com/docs"
|
|
19
|
+
Repository = "https://github.com/HeyZod/mansaapi-python"
|
|
20
|
+
|
|
21
|
+
[tool.hatch.build.targets.wheel]
|
|
22
|
+
packages = ["src/mansaapi"]
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
|
|
7
|
+
from .errors import MansaAPIError
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|
|
10
|
+
DEFAULT_BASE_URL = "https://mansaapi.com"
|
|
11
|
+
|
|
12
|
+
Params = Optional[Dict[str, Any]]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class _HttpClient:
|
|
16
|
+
def __init__(self, api_key: str, base_url: str, timeout: float) -> None:
|
|
17
|
+
self._api_key = api_key
|
|
18
|
+
self._base_url = base_url.rstrip("/")
|
|
19
|
+
self._timeout = timeout
|
|
20
|
+
self._session = requests.Session()
|
|
21
|
+
self._session.headers.update(
|
|
22
|
+
{
|
|
23
|
+
"Authorization": f"Bearer {api_key}",
|
|
24
|
+
"Content-Type": "application/json",
|
|
25
|
+
"User-Agent": f"mansaapi-python/{__version__}",
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def get(self, path: str, params: Params = None) -> Dict[str, Any]:
|
|
30
|
+
clean = {k: v for k, v in (params or {}).items() if v is not None}
|
|
31
|
+
resp = self._session.get(
|
|
32
|
+
f"{self._base_url}{path}", params=clean, timeout=self._timeout
|
|
33
|
+
)
|
|
34
|
+
return self._handle(resp)
|
|
35
|
+
|
|
36
|
+
def post(self, path: str, payload: Any) -> Dict[str, Any]:
|
|
37
|
+
resp = self._session.post(
|
|
38
|
+
f"{self._base_url}{path}", json=payload, timeout=self._timeout
|
|
39
|
+
)
|
|
40
|
+
return self._handle(resp)
|
|
41
|
+
|
|
42
|
+
@staticmethod
|
|
43
|
+
def _handle(resp: requests.Response) -> Dict[str, Any]:
|
|
44
|
+
try:
|
|
45
|
+
body = resp.json()
|
|
46
|
+
except ValueError:
|
|
47
|
+
raise MansaAPIError(
|
|
48
|
+
"INVALID_RESPONSE",
|
|
49
|
+
f"Non-JSON response (status {resp.status_code})",
|
|
50
|
+
resp.status_code,
|
|
51
|
+
resp.text,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if not resp.ok or body.get("success") is False:
|
|
55
|
+
err = body.get("error") or {}
|
|
56
|
+
raise MansaAPIError(
|
|
57
|
+
err.get("code", "UNKNOWN_ERROR"),
|
|
58
|
+
err.get("message", f"Request failed with status {resp.status_code}"),
|
|
59
|
+
resp.status_code,
|
|
60
|
+
body,
|
|
61
|
+
)
|
|
62
|
+
return body
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class _Markets:
|
|
66
|
+
def __init__(self, http: _HttpClient) -> None:
|
|
67
|
+
self._http = http
|
|
68
|
+
|
|
69
|
+
def get_exchanges(self) -> Dict[str, Any]:
|
|
70
|
+
return self._http.get("/api/v1/markets/exchanges")
|
|
71
|
+
|
|
72
|
+
def get_exchange(self, exchange_code: str) -> Dict[str, Any]:
|
|
73
|
+
return self._http.get(f"/api/v1/markets/exchanges/{exchange_code}")
|
|
74
|
+
|
|
75
|
+
def get_stocks(self, exchange_code: str, **params: Any) -> Dict[str, Any]:
|
|
76
|
+
return self._http.get(f"/api/v1/markets/exchanges/{exchange_code}/stocks", params)
|
|
77
|
+
|
|
78
|
+
def get_stock(self, exchange_code: str, ticker: str) -> Dict[str, Any]:
|
|
79
|
+
return self._http.get(f"/api/v1/markets/exchanges/{exchange_code}/stocks/{ticker}")
|
|
80
|
+
|
|
81
|
+
def get_movers(self, exchange_code: str, **params: Any) -> Dict[str, Any]:
|
|
82
|
+
return self._http.get(f"/api/v1/markets/exchanges/{exchange_code}/movers", params)
|
|
83
|
+
|
|
84
|
+
def get_pan_african_movers(self, **params: Any) -> Dict[str, Any]:
|
|
85
|
+
return self._http.get("/api/v1/markets/movers/pan-african", params)
|
|
86
|
+
|
|
87
|
+
def get_indices(self, exchange_code: str) -> Dict[str, Any]:
|
|
88
|
+
return self._http.get(f"/api/v1/markets/exchanges/{exchange_code}/indices")
|
|
89
|
+
|
|
90
|
+
def get_index(self, exchange_code: str, code: str) -> Dict[str, Any]:
|
|
91
|
+
return self._http.get(f"/api/v1/markets/exchanges/{exchange_code}/indices/{code}")
|
|
92
|
+
|
|
93
|
+
def get_etfs(self, exchange_code: str) -> Dict[str, Any]:
|
|
94
|
+
return self._http.get(f"/api/v1/markets/exchanges/{exchange_code}/etfs")
|
|
95
|
+
|
|
96
|
+
def get_forex(self) -> Dict[str, Any]:
|
|
97
|
+
return self._http.get("/api/v1/markets/forex")
|
|
98
|
+
|
|
99
|
+
def get_commodities(self) -> Dict[str, Any]:
|
|
100
|
+
return self._http.get("/api/v1/markets/commodities")
|
|
101
|
+
|
|
102
|
+
def search(self, query: str, **params: Any) -> Dict[str, Any]:
|
|
103
|
+
return self._http.get("/api/v1/markets/search", {"q": query, **params})
|
|
104
|
+
|
|
105
|
+
# Premium (Starter+)
|
|
106
|
+
def get_dividends(self, exchange_code: str, ticker: str, **params: Any) -> Dict[str, Any]:
|
|
107
|
+
return self._http.get(
|
|
108
|
+
f"/api/v1/markets/exchanges/{exchange_code}/dividends/{ticker}", params
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
def get_disclosures(self, exchange_code: str, **params: Any) -> Dict[str, Any]:
|
|
112
|
+
return self._http.get(
|
|
113
|
+
f"/api/v1/markets/exchanges/{exchange_code}/disclosures", params
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def get_recommendations(self, exchange_code: str, **params: Any) -> Dict[str, Any]:
|
|
117
|
+
return self._http.get(
|
|
118
|
+
f"/api/v1/markets/exchanges/{exchange_code}/recommendations", params
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Premium (Pro+)
|
|
122
|
+
def get_insider_trades(self, exchange_code: str, **params: Any) -> Dict[str, Any]:
|
|
123
|
+
return self._http.get(
|
|
124
|
+
f"/api/v1/markets/exchanges/{exchange_code}/insider-trades", params
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class _Identity:
|
|
129
|
+
def __init__(self, http: _HttpClient) -> None:
|
|
130
|
+
self._http = http
|
|
131
|
+
|
|
132
|
+
def get_banks(self, country: Optional[str] = None) -> Dict[str, Any]:
|
|
133
|
+
return self._http.get("/api/v1/identity/banks", {"country": country})
|
|
134
|
+
|
|
135
|
+
def get_bank(self, code: str) -> Dict[str, Any]:
|
|
136
|
+
return self._http.get(f"/api/v1/identity/banks/{code}")
|
|
137
|
+
|
|
138
|
+
def get_mobile_networks(self, country: Optional[str] = None) -> Dict[str, Any]:
|
|
139
|
+
return self._http.get("/api/v1/identity/mobile-networks", {"country": country})
|
|
140
|
+
|
|
141
|
+
def lookup_mobile_network(self, phone: str) -> Dict[str, Any]:
|
|
142
|
+
return self._http.get("/api/v1/identity/mobile-networks/lookup", {"phone": phone})
|
|
143
|
+
|
|
144
|
+
def get_currencies(self) -> Dict[str, Any]:
|
|
145
|
+
return self._http.get("/api/v1/identity/currencies")
|
|
146
|
+
|
|
147
|
+
def validate_nuban(self, account: str, bank_code: str) -> Dict[str, Any]:
|
|
148
|
+
return self._http.get(
|
|
149
|
+
"/api/v1/identity/nuban/validate",
|
|
150
|
+
{"account": account, "bank_code": bank_code},
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class _Location:
|
|
155
|
+
def __init__(self, http: _HttpClient) -> None:
|
|
156
|
+
self._http = http
|
|
157
|
+
|
|
158
|
+
def get_countries(self) -> Dict[str, Any]:
|
|
159
|
+
return self._http.get("/api/v1/location/countries")
|
|
160
|
+
|
|
161
|
+
def get_country(self, code: str) -> Dict[str, Any]:
|
|
162
|
+
return self._http.get(f"/api/v1/location/countries/{code}")
|
|
163
|
+
|
|
164
|
+
def get_states(self, country_code: str) -> Dict[str, Any]:
|
|
165
|
+
return self._http.get(f"/api/v1/location/countries/{country_code}/states")
|
|
166
|
+
|
|
167
|
+
def get_lgas(self, country_code: str, state_code: str) -> Dict[str, Any]:
|
|
168
|
+
return self._http.get(
|
|
169
|
+
f"/api/v1/location/countries/{country_code}/states/{state_code}/lgas"
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
def get_holidays(self, country_code: str, year: int) -> Dict[str, Any]:
|
|
173
|
+
return self._http.get(
|
|
174
|
+
f"/api/v1/location/countries/{country_code}/holidays/{year}"
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class _Keys:
|
|
179
|
+
def __init__(self, http: _HttpClient) -> None:
|
|
180
|
+
self._http = http
|
|
181
|
+
|
|
182
|
+
def create(self, name: str, email: str, project_description: Optional[str] = None) -> Dict[str, Any]:
|
|
183
|
+
return self._http.post(
|
|
184
|
+
"/api/v1/keys",
|
|
185
|
+
{
|
|
186
|
+
"name": name,
|
|
187
|
+
"email": email,
|
|
188
|
+
"tier": "standard",
|
|
189
|
+
"project_description": project_description,
|
|
190
|
+
},
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class MansaAPI:
|
|
195
|
+
"""Official Python client for the Mansa API.
|
|
196
|
+
|
|
197
|
+
Example:
|
|
198
|
+
from mansaapi import MansaAPI
|
|
199
|
+
|
|
200
|
+
mansa = MansaAPI(api_key="mansa_live_sk_...")
|
|
201
|
+
bank = mansa.identity.get_bank("058")
|
|
202
|
+
print(bank["data"]["name"]) # "Guaranty Trust Bank (GTBank)"
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
def __init__(
|
|
206
|
+
self,
|
|
207
|
+
api_key: str,
|
|
208
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
209
|
+
timeout: float = 30.0,
|
|
210
|
+
) -> None:
|
|
211
|
+
if not api_key:
|
|
212
|
+
raise ValueError("api_key is required. Get one free at https://mansaapi.com")
|
|
213
|
+
http = _HttpClient(api_key, base_url, timeout)
|
|
214
|
+
self.markets = _Markets(http)
|
|
215
|
+
self.identity = _Identity(http)
|
|
216
|
+
self.location = _Location(http)
|
|
217
|
+
self.keys = _Keys(http)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MansaAPIError(Exception):
|
|
7
|
+
"""Raised when the Mansa API returns an error response."""
|
|
8
|
+
|
|
9
|
+
def __init__(self, code: str, message: str, status: int, raw: Optional[Any] = None) -> None:
|
|
10
|
+
super().__init__(message)
|
|
11
|
+
self.code = code
|
|
12
|
+
self.message = message
|
|
13
|
+
self.status = status
|
|
14
|
+
self.raw = raw
|
|
15
|
+
|
|
16
|
+
def __repr__(self) -> str: # pragma: no cover
|
|
17
|
+
return f"MansaAPIError(code={self.code!r}, status={self.status}, message={self.message!r})"
|