kepler-insights 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.
- kepler_insights-1.0.0/.gitignore +75 -0
- kepler_insights-1.0.0/LICENSE +21 -0
- kepler_insights-1.0.0/PKG-INFO +153 -0
- kepler_insights-1.0.0/PUBLISH.md +128 -0
- kepler_insights-1.0.0/README.md +120 -0
- kepler_insights-1.0.0/pyproject.toml +63 -0
- kepler_insights-1.0.0/src/kepler_insights/__init__.py +54 -0
- kepler_insights-1.0.0/src/kepler_insights/_http.py +159 -0
- kepler_insights-1.0.0/src/kepler_insights/_version.py +1 -0
- kepler_insights-1.0.0/src/kepler_insights/client.py +301 -0
- kepler_insights-1.0.0/src/kepler_insights/errors.py +115 -0
- kepler_insights-1.0.0/src/kepler_insights/models.py +244 -0
- kepler_insights-1.0.0/tests/conftest.py +245 -0
- kepler_insights-1.0.0/tests/test_client.py +179 -0
- kepler_insights-1.0.0/tests/test_errors.py +152 -0
- kepler_insights-1.0.0/tests/test_jobs.py +109 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# --- Secrets (NEVER commit) ---
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
5
|
+
*.pem
|
|
6
|
+
*.p8
|
|
7
|
+
*.p12
|
|
8
|
+
*.key
|
|
9
|
+
secrets.json
|
|
10
|
+
credentials.json
|
|
11
|
+
|
|
12
|
+
# --- AWS / Lambda build artifacts ---
|
|
13
|
+
zips/
|
|
14
|
+
**/package/
|
|
15
|
+
*.zip
|
|
16
|
+
|
|
17
|
+
# --- Python ---
|
|
18
|
+
__pycache__/
|
|
19
|
+
*.py[cod]
|
|
20
|
+
*.egg-info/
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.ruff_cache/
|
|
24
|
+
.venv/
|
|
25
|
+
venv/
|
|
26
|
+
env/
|
|
27
|
+
|
|
28
|
+
# --- Node ---
|
|
29
|
+
node_modules/
|
|
30
|
+
npm-debug.log*
|
|
31
|
+
yarn-error.log*
|
|
32
|
+
|
|
33
|
+
# --- Netlify ---
|
|
34
|
+
.netlify/
|
|
35
|
+
|
|
36
|
+
# --- macOS ---
|
|
37
|
+
.DS_Store
|
|
38
|
+
.AppleDouble
|
|
39
|
+
.LSOverride
|
|
40
|
+
|
|
41
|
+
# --- Editors ---
|
|
42
|
+
.vscode/
|
|
43
|
+
.idea/
|
|
44
|
+
*.swp
|
|
45
|
+
*.swo
|
|
46
|
+
*~
|
|
47
|
+
|
|
48
|
+
# --- Logs / scratch ---
|
|
49
|
+
*.log
|
|
50
|
+
/tmp/
|
|
51
|
+
scratch/
|
|
52
|
+
|
|
53
|
+
# --- Ki_dev: keep website/ + api_site/ + docs/ + sdk-python/ + sdk-typescript/ in git, everything else (admin, outreach, PDFs) backed up separately ---
|
|
54
|
+
Ki_dev/*
|
|
55
|
+
!Ki_dev/website/
|
|
56
|
+
!Ki_dev/api_site/
|
|
57
|
+
!Ki_dev/docs/
|
|
58
|
+
!Ki_dev/sdk-python/
|
|
59
|
+
!Ki_dev/sdk-typescript/
|
|
60
|
+
|
|
61
|
+
# Python SDK build artifacts
|
|
62
|
+
Ki_dev/sdk-python/dist/
|
|
63
|
+
Ki_dev/sdk-python/build/
|
|
64
|
+
Ki_dev/sdk-python/*.egg-info/
|
|
65
|
+
Ki_dev/sdk-python/.pytest_cache/
|
|
66
|
+
Ki_dev/sdk-python/.venv/
|
|
67
|
+
|
|
68
|
+
# TypeScript SDK build artifacts
|
|
69
|
+
Ki_dev/sdk-typescript/node_modules/
|
|
70
|
+
Ki_dev/sdk-typescript/dist/
|
|
71
|
+
Ki_dev/sdk-typescript/.turbo/
|
|
72
|
+
Ki_dev/sdk-typescript/coverage/
|
|
73
|
+
|
|
74
|
+
# --- Claude Code worktrees ---
|
|
75
|
+
.claude/worktrees/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kepler Insights
|
|
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,153 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kepler-insights
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK for the Kepler Insights API — curated company-scoring intelligence over a 67-signal engine.
|
|
5
|
+
Project-URL: Homepage, https://api.keplerinsights.us
|
|
6
|
+
Project-URL: Documentation, https://docs.keplerinsights.us
|
|
7
|
+
Project-URL: Support, https://console.keplerinsights.us
|
|
8
|
+
Author-email: Kepler Insights <noah@keplerinsights.us>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: api-client,company-intelligence,kepler,scoring,vc
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: httpx<1.0,>=0.27
|
|
26
|
+
Requires-Dist: pydantic<3.0,>=2.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: build>=1.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# Kepler Insights — Python SDK
|
|
35
|
+
|
|
36
|
+
Official Python SDK for the [Kepler Insights API](https://api.keplerinsights.us) — curated company-scoring intelligence over a 67-signal engine.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install kepler-insights
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Requires Python 3.10+. Depends on [httpx](https://www.python-httpx.org/) and [pydantic v2](https://docs.pydantic.dev/latest/).
|
|
45
|
+
|
|
46
|
+
## Quickstart
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from kepler_insights import Kepler
|
|
50
|
+
|
|
51
|
+
with Kepler(api_key="ki_live_...") as client:
|
|
52
|
+
score = client.score("stripe.com")
|
|
53
|
+
print(f"{score.domain}: {score.ki_rating} ({score.composite_score:.1f})")
|
|
54
|
+
print(f" team: {score.buckets.team_structure:.1f}")
|
|
55
|
+
print(f" market: {score.buckets.market_position:.1f}")
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Sandbox keys (`ki_test_...`) accept only the 4 canned domains — `acme.test`, `unicorn.test`, `struggling.test`, `cohort.test`. See the [Sandbox guide](https://docs.keplerinsights.us/sandbox).
|
|
59
|
+
|
|
60
|
+
## API surface
|
|
61
|
+
|
|
62
|
+
| Method | Endpoint | Returns |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| `client.score(domain)` | POST `/v1/score` | `Score` |
|
|
65
|
+
| `client.get_score(domain)` | GET `/v1/score/{domain}` | `Score` |
|
|
66
|
+
| `client.start_score(domain)` | POST `/v1/score?wait=false` | `Job` (Growth+) |
|
|
67
|
+
| `client.get_job(job_id)` | GET `/v1/jobs/{job_id}` | `JobResponse` |
|
|
68
|
+
| `client.history(domain, limit=, cursor=)` | GET `/v1/score/{domain}/history` | `HistoryPage` |
|
|
69
|
+
| `client.iter_history(domain, max_records=)` | (auto-paginates) | iterator of `HistoryRecord` |
|
|
70
|
+
| `client.cohort(domain)` | GET `/v1/company/{domain}/cohort` | `Cohort` |
|
|
71
|
+
| `client.confidence(domain)` | GET `/v1/company/{domain}/confidence` | `Confidence` |
|
|
72
|
+
| `client.distribution()` | GET `/v1/distribution` | `Distribution` |
|
|
73
|
+
| `client.movers(window)` | GET `/v1/movers` | `Movers` |
|
|
74
|
+
| `client.signals()` | GET `/v1/signals` | `SignalsManifest` |
|
|
75
|
+
| `client.usage()` | GET `/v1/usage` | `Usage` |
|
|
76
|
+
|
|
77
|
+
## Async cold scoring
|
|
78
|
+
|
|
79
|
+
Cold scoring takes 30–60 seconds. On Growth and above, you can start a job and poll without holding an HTTP connection open:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
job = client.start_score("stripe.com") # returns immediately
|
|
83
|
+
score = job.wait(timeout=180) # blocks until complete; raises on timeout
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
If the API short-circuits to a cached-fresh response (no cold work needed), `start_score` returns a `Job` already in the `complete` state — `wait()` returns instantly. This mirrors Stripe's `payment_intent` "no action needed" pattern.
|
|
87
|
+
|
|
88
|
+
## Error handling
|
|
89
|
+
|
|
90
|
+
Every error inherits from `KeplerError`. Branch on the specific subclass or the stable `error.code` string:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from kepler_insights import (
|
|
94
|
+
Kepler,
|
|
95
|
+
AuthError,
|
|
96
|
+
ColdBudgetExhausted,
|
|
97
|
+
FreeTierSandboxOnly,
|
|
98
|
+
NotFound,
|
|
99
|
+
RateLimitError,
|
|
100
|
+
ScoringTimeout,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
score = client.score("stripe.com")
|
|
105
|
+
except FreeTierSandboxOnly:
|
|
106
|
+
print("Upgrade to Starter for live scoring.")
|
|
107
|
+
except ColdBudgetExhausted as e:
|
|
108
|
+
print(f"Monthly cap hit. Resets in {e.retry_after}s. Upgrade for more.")
|
|
109
|
+
except RateLimitError as e:
|
|
110
|
+
print(f"Rate limited. Retry in {e.retry_after}s.")
|
|
111
|
+
except ScoringTimeout:
|
|
112
|
+
print("Cold scoring exceeded sync budget — use start_score() for async.")
|
|
113
|
+
except NotFound:
|
|
114
|
+
print("Never scored. Trigger one with score(domain).")
|
|
115
|
+
except AuthError:
|
|
116
|
+
print("Invalid or revoked API key.")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The SDK auto-retries on 5xx and network errors with exponential backoff (3 attempts by default). It never retries 4xx — those are caller errors.
|
|
120
|
+
|
|
121
|
+
## Configuration
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
client = Kepler(
|
|
125
|
+
api_key="ki_live_...",
|
|
126
|
+
base_url="https://api.keplerinsights.us", # override only for testing
|
|
127
|
+
timeout=70.0, # per-request timeout (s)
|
|
128
|
+
retries=3, # 5xx retry attempts
|
|
129
|
+
)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
For custom transports (proxies, mTLS, etc.) inject your own `httpx.Client`:
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
import httpx
|
|
136
|
+
custom = httpx.Client(timeout=120, transport=httpx.HTTPTransport(retries=0))
|
|
137
|
+
client = Kepler(api_key="ki_live_...", http_client=custom)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Development
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
git clone <repo>
|
|
144
|
+
cd Ki_dev/sdk-python
|
|
145
|
+
python3 -m venv .venv
|
|
146
|
+
source .venv/bin/activate
|
|
147
|
+
pip install -e ".[dev]"
|
|
148
|
+
pytest
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## License
|
|
152
|
+
|
|
153
|
+
MIT. The API itself is proprietary; the SDK wrapper is MIT-licensed so you can vendor it freely.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Publishing `kepler-insights` to PyPI
|
|
2
|
+
|
|
3
|
+
Run this checklist at the **coordinated API launch event** (same window as Mintlify, Instatus, Stripe SKU creation, and the `api.keplerinsights.us` DNS flip). All code is pre-shipped (F1, 2026-05-12) — this checklist just publishes.
|
|
4
|
+
|
|
5
|
+
## 0. Prereqs
|
|
6
|
+
|
|
7
|
+
- A PyPI account on the Kepler Insights org (https://pypi.org). Reserve the `kepler-insights` name well before launch event by uploading version 0.0.1 placeholder, or check it's still available.
|
|
8
|
+
- A TestPyPI account (https://test.pypi.org) for the dry run.
|
|
9
|
+
- A PyPI API token scoped to `kepler-insights` (Account settings → API tokens → "scope to project").
|
|
10
|
+
- A TestPyPI API token (separate token, separate account).
|
|
11
|
+
- Python 3.11+ locally with `build` and `twine` available.
|
|
12
|
+
|
|
13
|
+
## 1. Pre-flight checks
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
cd Ki_dev/sdk-python
|
|
17
|
+
|
|
18
|
+
# Clean state
|
|
19
|
+
rm -rf dist/ build/ *.egg-info src/*.egg-info
|
|
20
|
+
|
|
21
|
+
# Run tests
|
|
22
|
+
python3.13 -m venv .venv
|
|
23
|
+
source .venv/bin/activate
|
|
24
|
+
pip install --upgrade pip
|
|
25
|
+
pip install -e ".[dev]"
|
|
26
|
+
pytest # expect 33 passing
|
|
27
|
+
|
|
28
|
+
# Lint
|
|
29
|
+
ruff check src tests
|
|
30
|
+
|
|
31
|
+
# Confirm version is what you want to publish
|
|
32
|
+
grep '__version__' src/kepler_insights/_version.py # expect 1.0.0
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 2. Build artifacts
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
python -m build
|
|
39
|
+
ls -la dist/
|
|
40
|
+
# expect:
|
|
41
|
+
# kepler_insights-1.0.0-py3-none-any.whl
|
|
42
|
+
# kepler_insights-1.0.0.tar.gz
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Inspect the sdist contents before uploading:
|
|
46
|
+
```bash
|
|
47
|
+
tar -tzf dist/kepler_insights-1.0.0.tar.gz | head -30
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Should include `src/kepler_insights/*.py`, `pyproject.toml`, `README.md`, `LICENSE`. Should NOT include `.venv/`, `.pytest_cache/`, `tests/` (by hatchling default).
|
|
51
|
+
|
|
52
|
+
## 3. Upload to TestPyPI first
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install --upgrade twine
|
|
56
|
+
twine upload --repository testpypi dist/*
|
|
57
|
+
# username: __token__
|
|
58
|
+
# password: <TestPyPI API token starting `pypi-...`>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Verify in a clean venv that the install works:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
deactivate
|
|
65
|
+
rm -rf /tmp/sdk-verify && python3.13 -m venv /tmp/sdk-verify
|
|
66
|
+
/tmp/sdk-verify/bin/pip install --index-url https://test.pypi.org/simple/ \
|
|
67
|
+
--extra-index-url https://pypi.org/simple/ \
|
|
68
|
+
kepler-insights
|
|
69
|
+
/tmp/sdk-verify/bin/python -c "from kepler_insights import Kepler; print(Kepler)"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The `--extra-index-url` to real PyPI is required because TestPyPI doesn't host httpx/pydantic.
|
|
73
|
+
|
|
74
|
+
## 4. Upload to production PyPI
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
source .venv/bin/activate
|
|
78
|
+
twine upload dist/*
|
|
79
|
+
# username: __token__
|
|
80
|
+
# password: <PyPI production API token>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 5. Post-publish verification
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Fresh venv, no override
|
|
87
|
+
rm -rf /tmp/sdk-prod-verify && python3.13 -m venv /tmp/sdk-prod-verify
|
|
88
|
+
/tmp/sdk-prod-verify/bin/pip install kepler-insights
|
|
89
|
+
/tmp/sdk-prod-verify/bin/python -c "
|
|
90
|
+
from kepler_insights import Kepler, __version__
|
|
91
|
+
print('version:', __version__)
|
|
92
|
+
print('Kepler client class:', Kepler)
|
|
93
|
+
"
|
|
94
|
+
|
|
95
|
+
# Page check
|
|
96
|
+
open https://pypi.org/project/kepler-insights/
|
|
97
|
+
# expect: project page shows version 1.0.0, links to api.keplerinsights.us,
|
|
98
|
+
# README rendered cleanly
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## 6. Update downstream
|
|
102
|
+
|
|
103
|
+
- [ ] Update [Ki_dev/docs/quickstart.mdx](../docs/quickstart.mdx) install instruction if needed.
|
|
104
|
+
- [ ] Update [Ki_dev/api_site/index.html](../api_site/index.html) "Install the SDK" hero with the `pip install kepler-insights` snippet.
|
|
105
|
+
- [ ] Announce in the launch blast email.
|
|
106
|
+
|
|
107
|
+
## Rollback / yank
|
|
108
|
+
|
|
109
|
+
If a release is broken:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Yank the version (still installable by explicit pin, but no longer the default)
|
|
113
|
+
twine yank kepler-insights 1.0.0
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Yank is reversible. Don't `twine delete` — once deleted, the version number can never be reused.
|
|
117
|
+
|
|
118
|
+
For a hotfix release: bump `_version.py` to `1.0.1`, re-test, re-build, re-upload. PyPI doesn't allow re-uploading a version that already exists.
|
|
119
|
+
|
|
120
|
+
## Versioning policy
|
|
121
|
+
|
|
122
|
+
Semantic versioning. The OpenAPI spec at `Ki_dev/docs/openapi.yaml` is the source of truth for breaking-change detection:
|
|
123
|
+
|
|
124
|
+
- **Patch (1.0.x)** — bug fixes, no public-surface changes
|
|
125
|
+
- **Minor (1.x.0)** — additive: new methods, new fields on response models (Pydantic `extra="allow"` keeps old code working)
|
|
126
|
+
- **Major (x.0.0)** — removal or rename of a public method / model field
|
|
127
|
+
|
|
128
|
+
If the API ships a v2, this SDK ships a `2.0.0` adding a `KeplerV2` client class alongside `Kepler` (which keeps targeting v1 endpoints) — same pattern as `openai.OpenAI` vs `openai.AzureOpenAI`. Don't break v1 callers when v2 lands.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Kepler Insights — Python SDK
|
|
2
|
+
|
|
3
|
+
Official Python SDK for the [Kepler Insights API](https://api.keplerinsights.us) — curated company-scoring intelligence over a 67-signal engine.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install kepler-insights
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Python 3.10+. Depends on [httpx](https://www.python-httpx.org/) and [pydantic v2](https://docs.pydantic.dev/latest/).
|
|
12
|
+
|
|
13
|
+
## Quickstart
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from kepler_insights import Kepler
|
|
17
|
+
|
|
18
|
+
with Kepler(api_key="ki_live_...") as client:
|
|
19
|
+
score = client.score("stripe.com")
|
|
20
|
+
print(f"{score.domain}: {score.ki_rating} ({score.composite_score:.1f})")
|
|
21
|
+
print(f" team: {score.buckets.team_structure:.1f}")
|
|
22
|
+
print(f" market: {score.buckets.market_position:.1f}")
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Sandbox keys (`ki_test_...`) accept only the 4 canned domains — `acme.test`, `unicorn.test`, `struggling.test`, `cohort.test`. See the [Sandbox guide](https://docs.keplerinsights.us/sandbox).
|
|
26
|
+
|
|
27
|
+
## API surface
|
|
28
|
+
|
|
29
|
+
| Method | Endpoint | Returns |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `client.score(domain)` | POST `/v1/score` | `Score` |
|
|
32
|
+
| `client.get_score(domain)` | GET `/v1/score/{domain}` | `Score` |
|
|
33
|
+
| `client.start_score(domain)` | POST `/v1/score?wait=false` | `Job` (Growth+) |
|
|
34
|
+
| `client.get_job(job_id)` | GET `/v1/jobs/{job_id}` | `JobResponse` |
|
|
35
|
+
| `client.history(domain, limit=, cursor=)` | GET `/v1/score/{domain}/history` | `HistoryPage` |
|
|
36
|
+
| `client.iter_history(domain, max_records=)` | (auto-paginates) | iterator of `HistoryRecord` |
|
|
37
|
+
| `client.cohort(domain)` | GET `/v1/company/{domain}/cohort` | `Cohort` |
|
|
38
|
+
| `client.confidence(domain)` | GET `/v1/company/{domain}/confidence` | `Confidence` |
|
|
39
|
+
| `client.distribution()` | GET `/v1/distribution` | `Distribution` |
|
|
40
|
+
| `client.movers(window)` | GET `/v1/movers` | `Movers` |
|
|
41
|
+
| `client.signals()` | GET `/v1/signals` | `SignalsManifest` |
|
|
42
|
+
| `client.usage()` | GET `/v1/usage` | `Usage` |
|
|
43
|
+
|
|
44
|
+
## Async cold scoring
|
|
45
|
+
|
|
46
|
+
Cold scoring takes 30–60 seconds. On Growth and above, you can start a job and poll without holding an HTTP connection open:
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
job = client.start_score("stripe.com") # returns immediately
|
|
50
|
+
score = job.wait(timeout=180) # blocks until complete; raises on timeout
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If the API short-circuits to a cached-fresh response (no cold work needed), `start_score` returns a `Job` already in the `complete` state — `wait()` returns instantly. This mirrors Stripe's `payment_intent` "no action needed" pattern.
|
|
54
|
+
|
|
55
|
+
## Error handling
|
|
56
|
+
|
|
57
|
+
Every error inherits from `KeplerError`. Branch on the specific subclass or the stable `error.code` string:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from kepler_insights import (
|
|
61
|
+
Kepler,
|
|
62
|
+
AuthError,
|
|
63
|
+
ColdBudgetExhausted,
|
|
64
|
+
FreeTierSandboxOnly,
|
|
65
|
+
NotFound,
|
|
66
|
+
RateLimitError,
|
|
67
|
+
ScoringTimeout,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
score = client.score("stripe.com")
|
|
72
|
+
except FreeTierSandboxOnly:
|
|
73
|
+
print("Upgrade to Starter for live scoring.")
|
|
74
|
+
except ColdBudgetExhausted as e:
|
|
75
|
+
print(f"Monthly cap hit. Resets in {e.retry_after}s. Upgrade for more.")
|
|
76
|
+
except RateLimitError as e:
|
|
77
|
+
print(f"Rate limited. Retry in {e.retry_after}s.")
|
|
78
|
+
except ScoringTimeout:
|
|
79
|
+
print("Cold scoring exceeded sync budget — use start_score() for async.")
|
|
80
|
+
except NotFound:
|
|
81
|
+
print("Never scored. Trigger one with score(domain).")
|
|
82
|
+
except AuthError:
|
|
83
|
+
print("Invalid or revoked API key.")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The SDK auto-retries on 5xx and network errors with exponential backoff (3 attempts by default). It never retries 4xx — those are caller errors.
|
|
87
|
+
|
|
88
|
+
## Configuration
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
client = Kepler(
|
|
92
|
+
api_key="ki_live_...",
|
|
93
|
+
base_url="https://api.keplerinsights.us", # override only for testing
|
|
94
|
+
timeout=70.0, # per-request timeout (s)
|
|
95
|
+
retries=3, # 5xx retry attempts
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
For custom transports (proxies, mTLS, etc.) inject your own `httpx.Client`:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
import httpx
|
|
103
|
+
custom = httpx.Client(timeout=120, transport=httpx.HTTPTransport(retries=0))
|
|
104
|
+
client = Kepler(api_key="ki_live_...", http_client=custom)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Development
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
git clone <repo>
|
|
111
|
+
cd Ki_dev/sdk-python
|
|
112
|
+
python3 -m venv .venv
|
|
113
|
+
source .venv/bin/activate
|
|
114
|
+
pip install -e ".[dev]"
|
|
115
|
+
pytest
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT. The API itself is proprietary; the SDK wrapper is MIT-licensed so you can vendor it freely.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.18"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "kepler-insights"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Official Python SDK for the Kepler Insights API — curated company-scoring intelligence over a 67-signal engine."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
authors = [{ name = "Kepler Insights", email = "noah@keplerinsights.us" }]
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
keywords = ["kepler", "scoring", "company-intelligence", "vc", "api-client"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
|
+
"Typing :: Typed",
|
|
28
|
+
]
|
|
29
|
+
dependencies = [
|
|
30
|
+
"httpx>=0.27,<1.0",
|
|
31
|
+
"pydantic>=2.0,<3.0",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://api.keplerinsights.us"
|
|
36
|
+
Documentation = "https://docs.keplerinsights.us"
|
|
37
|
+
Support = "https://console.keplerinsights.us"
|
|
38
|
+
|
|
39
|
+
[project.optional-dependencies]
|
|
40
|
+
dev = [
|
|
41
|
+
"pytest>=8.0",
|
|
42
|
+
"respx>=0.21",
|
|
43
|
+
"ruff>=0.5",
|
|
44
|
+
"build>=1.0",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[tool.hatch.version]
|
|
48
|
+
path = "src/kepler_insights/_version.py"
|
|
49
|
+
|
|
50
|
+
[tool.hatch.build.targets.wheel]
|
|
51
|
+
packages = ["src/kepler_insights"]
|
|
52
|
+
|
|
53
|
+
[tool.pytest.ini_options]
|
|
54
|
+
testpaths = ["tests"]
|
|
55
|
+
addopts = "-ra --strict-markers"
|
|
56
|
+
pythonpath = ["src"]
|
|
57
|
+
|
|
58
|
+
[tool.ruff]
|
|
59
|
+
line-length = 100
|
|
60
|
+
target-version = "py310"
|
|
61
|
+
|
|
62
|
+
[tool.ruff.lint]
|
|
63
|
+
select = ["E", "F", "I", "B", "UP"]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Kepler Insights API — official Python SDK.
|
|
2
|
+
|
|
3
|
+
Quickstart
|
|
4
|
+
----------
|
|
5
|
+
|
|
6
|
+
>>> from kepler_insights import Kepler
|
|
7
|
+
>>> with Kepler(api_key="ki_live_...") as client:
|
|
8
|
+
... score = client.score("stripe.com")
|
|
9
|
+
... print(score.ki_rating, score.composite_score)
|
|
10
|
+
|
|
11
|
+
See https://docs.keplerinsights.us for the full guide.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from ._version import __version__
|
|
15
|
+
from .client import Kepler, Job
|
|
16
|
+
from . import errors, models
|
|
17
|
+
|
|
18
|
+
# Common error classes re-exported at the top level for ergonomic imports:
|
|
19
|
+
# from kepler_insights import KeplerError, RateLimitError, ColdBudgetExhausted
|
|
20
|
+
from .errors import (
|
|
21
|
+
KeplerError,
|
|
22
|
+
AuthError,
|
|
23
|
+
FreeTierSandboxOnly,
|
|
24
|
+
Forbidden,
|
|
25
|
+
NotFound,
|
|
26
|
+
ValidationError,
|
|
27
|
+
RateLimitError,
|
|
28
|
+
ColdBudgetExhausted,
|
|
29
|
+
ServerError,
|
|
30
|
+
ScoringTimeout,
|
|
31
|
+
JobTimeout,
|
|
32
|
+
JobFailed,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"__version__",
|
|
37
|
+
"Kepler",
|
|
38
|
+
"Job",
|
|
39
|
+
"errors",
|
|
40
|
+
"models",
|
|
41
|
+
# Error classes
|
|
42
|
+
"KeplerError",
|
|
43
|
+
"AuthError",
|
|
44
|
+
"FreeTierSandboxOnly",
|
|
45
|
+
"Forbidden",
|
|
46
|
+
"NotFound",
|
|
47
|
+
"ValidationError",
|
|
48
|
+
"RateLimitError",
|
|
49
|
+
"ColdBudgetExhausted",
|
|
50
|
+
"ServerError",
|
|
51
|
+
"ScoringTimeout",
|
|
52
|
+
"JobTimeout",
|
|
53
|
+
"JobFailed",
|
|
54
|
+
]
|