isa-sdk 1.0.0__py3-none-any.whl
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.
- isa_sdk/__init__.py +60 -0
- isa_sdk/account.py +5 -0
- isa_sdk/catalog.py +5 -0
- isa_sdk/core.py +5 -0
- isa_sdk/proxy.py +5 -0
- isa_sdk/py.typed +0 -0
- isa_sdk/rapidsign.py +5 -0
- isa_sdk/webhooks.py +5 -0
- isa_sdk/zyins.py +50 -0
- isa_sdk-1.0.0.dist-info/METADATA +328 -0
- isa_sdk-1.0.0.dist-info/RECORD +100 -0
- isa_sdk-1.0.0.dist-info/WHEEL +4 -0
- sah_sdk/__contract__.py +257 -0
- sah_sdk/__init__.py +133 -0
- sah_sdk/_codemod/__init__.py +25 -0
- sah_sdk/_codemod/__main__.py +45 -0
- sah_sdk/_codemod/rewriter.py +179 -0
- sah_sdk/account/__init__.py +142 -0
- sah_sdk/account/_op.py +86 -0
- sah_sdk/account/branding.py +107 -0
- sah_sdk/account/cases.py +173 -0
- sah_sdk/account/email.py +92 -0
- sah_sdk/account/preferences.py +102 -0
- sah_sdk/account/reference_data.py +111 -0
- sah_sdk/catalog/__init__.py +36 -0
- sah_sdk/catalog/carriers.py +107 -0
- sah_sdk/catalog/conditions.py +44 -0
- sah_sdk/catalog/errors.py +89 -0
- sah_sdk/catalog/medications.py +1909 -0
- sah_sdk/catalog/products.py +312 -0
- sah_sdk/catalog/scopes.py +35 -0
- sah_sdk/catalog/sign_events.py +24 -0
- sah_sdk/catalog/states.py +236 -0
- sah_sdk/core/__init__.py +56 -0
- sah_sdk/core/auth.py +95 -0
- sah_sdk/core/bootstrap.py +135 -0
- sah_sdk/core/constants.py +117 -0
- sah_sdk/core/credential_store.py +96 -0
- sah_sdk/core/debug.py +157 -0
- sah_sdk/core/env.py +73 -0
- sah_sdk/core/envelope.py +93 -0
- sah_sdk/core/errors.py +388 -0
- sah_sdk/core/idempotency.py +16 -0
- sah_sdk/core/json_response.py +40 -0
- sah_sdk/core/license_hmac.py +134 -0
- sah_sdk/core/session.py +336 -0
- sah_sdk/core/sign_request.py +133 -0
- sah_sdk/core/transport.py +102 -0
- sah_sdk/core/value_types.py +96 -0
- sah_sdk/core/wire.py +70 -0
- sah_sdk/isa.py +1635 -0
- sah_sdk/proxy/__init__.py +88 -0
- sah_sdk/proxy/call.py +302 -0
- sah_sdk/py.typed +0 -0
- sah_sdk/rapidsign/__init__.py +30 -0
- sah_sdk/webhooks.py +29 -0
- sah_sdk/zyins/__init__.py +210 -0
- sah_sdk/zyins/account_namespaces.py +162 -0
- sah_sdk/zyins/applicant.py +180 -0
- sah_sdk/zyins/branding.py +75 -0
- sah_sdk/zyins/bundled_api_versions.py +72 -0
- sah_sdk/zyins/cases/__init__.py +254 -0
- sah_sdk/zyins/cases/storage.py +104 -0
- sah_sdk/zyins/cases/zero_knowledge.py +269 -0
- sah_sdk/zyins/cases.py +141 -0
- sah_sdk/zyins/cases_storage.py +19 -0
- sah_sdk/zyins/client.py +431 -0
- sah_sdk/zyins/coverage.py +111 -0
- sah_sdk/zyins/credential_state.py +151 -0
- sah_sdk/zyins/datasets.py +35 -0
- sah_sdk/zyins/datasets_v3.py +764 -0
- sah_sdk/zyins/health.py +47 -0
- sah_sdk/zyins/isa_options.py +335 -0
- sah_sdk/zyins/license.py +46 -0
- sah_sdk/zyins/licenses.py +122 -0
- sah_sdk/zyins/licenses_facade.py +227 -0
- sah_sdk/zyins/logos.py +147 -0
- sah_sdk/zyins/measurements.py +279 -0
- sah_sdk/zyins/plan_info_label.py +128 -0
- sah_sdk/zyins/preferences.py +74 -0
- sah_sdk/zyins/prequalify.py +282 -0
- sah_sdk/zyins/prequalify_legacy_blob.py +44 -0
- sah_sdk/zyins/prequalify_v3.py +904 -0
- sah_sdk/zyins/product.py +216 -0
- sah_sdk/zyins/products.py +54 -0
- sah_sdk/zyins/quote.py +80 -0
- sah_sdk/zyins/quote_v3.py +153 -0
- sah_sdk/zyins/reference/__init__.py +435 -0
- sah_sdk/zyins/reference/_make_key.py +39 -0
- sah_sdk/zyins/reference/autocomplete_algorithm.py +406 -0
- sah_sdk/zyins/reference/autocorrector.py +325 -0
- sah_sdk/zyins/reference/concept.py +173 -0
- sah_sdk/zyins/reference/index.py +260 -0
- sah_sdk/zyins/reference/match_algorithm.py +111 -0
- sah_sdk/zyins/reference/reference_index.py +215 -0
- sah_sdk/zyins/reference/sort.py +31 -0
- sah_sdk/zyins/reference/suggestion.py +77 -0
- sah_sdk/zyins/reference_data.py +42 -0
- sah_sdk/zyins/reference_v3.py +394 -0
- sah_sdk/zyins/usage.py +32 -0
isa_sdk/__init__.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""``isa_sdk`` — cross-language naming alias for :mod:`sah_sdk`.
|
|
2
|
+
|
|
3
|
+
The TypeScript SDK ships as ``@isa-sdk/sdk``; the canonical Python
|
|
4
|
+
import path going forward is ``isa_sdk``. To avoid a hard rename break
|
|
5
|
+
during the transition, this package re-exports the entire ``sah_sdk``
|
|
6
|
+
public surface verbatim. Either spelling resolves to the same objects:
|
|
7
|
+
|
|
8
|
+
>>> import sah_sdk, isa_sdk
|
|
9
|
+
>>> isa_sdk.Isa is sah_sdk.Isa
|
|
10
|
+
True
|
|
11
|
+
|
|
12
|
+
Submodules (``isa_sdk.zyins``, ``isa_sdk.core``, …) resolve to the
|
|
13
|
+
corresponding ``sah_sdk`` modules, so ``from isa_sdk.zyins import
|
|
14
|
+
Applicant`` resolves natively under both runtime and mypy.
|
|
15
|
+
|
|
16
|
+
The legacy ``sah_sdk`` import path remains supported for one minor
|
|
17
|
+
release; new code should prefer ``isa_sdk``. Sunset target: v0.7.0.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import importlib
|
|
23
|
+
import pkgutil
|
|
24
|
+
import sys
|
|
25
|
+
|
|
26
|
+
from sah_sdk import * # noqa: F403 (re-export public surface)
|
|
27
|
+
from sah_sdk import __all__ as _sah_all
|
|
28
|
+
from sah_sdk import __version__
|
|
29
|
+
|
|
30
|
+
_SUBMODULE_ALIASES = (
|
|
31
|
+
"account",
|
|
32
|
+
"catalog",
|
|
33
|
+
"core",
|
|
34
|
+
"proxy",
|
|
35
|
+
"rapidsign",
|
|
36
|
+
"webhooks",
|
|
37
|
+
"zyins",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _install_aliases() -> None:
|
|
42
|
+
for name in _SUBMODULE_ALIASES:
|
|
43
|
+
source = importlib.import_module(f"sah_sdk.{name}")
|
|
44
|
+
target_name = f"{__name__}.{name}"
|
|
45
|
+
sys.modules[target_name] = source
|
|
46
|
+
setattr(sys.modules[__name__], name, source)
|
|
47
|
+
|
|
48
|
+
source_path = getattr(source, "__path__", None)
|
|
49
|
+
if source_path is None:
|
|
50
|
+
continue
|
|
51
|
+
|
|
52
|
+
for module_info in pkgutil.walk_packages(source_path, f"sah_sdk.{name}."):
|
|
53
|
+
child = importlib.import_module(module_info.name)
|
|
54
|
+
child_target = f"{__name__}.{module_info.name.removeprefix('sah_sdk.')}"
|
|
55
|
+
sys.modules[child_target] = child
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
_install_aliases()
|
|
59
|
+
|
|
60
|
+
__all__ = [*_sah_all, "__version__"]
|
isa_sdk/account.py
ADDED
isa_sdk/catalog.py
ADDED
isa_sdk/core.py
ADDED
isa_sdk/proxy.py
ADDED
isa_sdk/py.typed
ADDED
|
File without changes
|
isa_sdk/rapidsign.py
ADDED
isa_sdk/webhooks.py
ADDED
isa_sdk/zyins.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""``isa_sdk.zyins`` — alias for :mod:`sah_sdk.zyins`.
|
|
2
|
+
|
|
3
|
+
Importing here is identical to importing from ``sah_sdk.zyins``; both
|
|
4
|
+
spellings yield the same module object via the parent package's
|
|
5
|
+
``sys.modules`` binding (see :mod:`isa_sdk`).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from sah_sdk.zyins import * # noqa: F403
|
|
11
|
+
from sah_sdk.zyins import ( # noqa: F401
|
|
12
|
+
Applicant,
|
|
13
|
+
Carrier,
|
|
14
|
+
Condition,
|
|
15
|
+
Coverage,
|
|
16
|
+
CoverageType,
|
|
17
|
+
Eligibility,
|
|
18
|
+
Envelope,
|
|
19
|
+
Height,
|
|
20
|
+
HeightParseError,
|
|
21
|
+
IsaApiError,
|
|
22
|
+
IsaConfigError,
|
|
23
|
+
IsaIdempotencyConflictError,
|
|
24
|
+
IsaRateLimitError,
|
|
25
|
+
Medication,
|
|
26
|
+
NicotineDuration,
|
|
27
|
+
NicotineProductUsage,
|
|
28
|
+
NicotineUsage,
|
|
29
|
+
NicotineUsageInput,
|
|
30
|
+
PlanProduct,
|
|
31
|
+
Premium,
|
|
32
|
+
PrequalifyError,
|
|
33
|
+
PrequalifyInput,
|
|
34
|
+
PrequalifyPlan,
|
|
35
|
+
PrequalifyResult,
|
|
36
|
+
Product,
|
|
37
|
+
ProductCatalog,
|
|
38
|
+
ProductSelection,
|
|
39
|
+
ProductType,
|
|
40
|
+
QuoteInput,
|
|
41
|
+
QuoteResult,
|
|
42
|
+
QuoteType,
|
|
43
|
+
RateLimitError,
|
|
44
|
+
RawResponse,
|
|
45
|
+
Sex,
|
|
46
|
+
Weight,
|
|
47
|
+
WeightParseError,
|
|
48
|
+
ZyInsClient,
|
|
49
|
+
ZyInsError,
|
|
50
|
+
)
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: isa-sdk
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Unified Python SDK for ISA APIs (zyins, rapidsign, proxy).
|
|
5
|
+
Project-URL: Homepage, https://github.com/Software-Automation-Holdings-LLC/isa-platform
|
|
6
|
+
Project-URL: Source, https://github.com/Software-Automation-Holdings-LLC/isa-platform
|
|
7
|
+
Author: Software Automation Holdings, LLC
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Keywords: insurance,isa,rapidsign,sdk,zyins
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: cryptography>=42
|
|
22
|
+
Requires-Dist: httpx>=0.27
|
|
23
|
+
Requires-Dist: libcst>=1.4
|
|
24
|
+
Requires-Dist: pydantic>=2.6
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
27
|
+
Requires-Dist: libcst>=1.4; extra == 'dev'
|
|
28
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# sah-sdk
|
|
36
|
+
|
|
37
|
+
Python SDK for the [Best Plan Pro API](https://docs.isaapi.com) — powered by the ZyINS engine. Mirrors the
|
|
38
|
+
canonical TypeScript SDK at `packages/zyins/js/` with Python-idiomatic
|
|
39
|
+
naming (`snake_case`) and pydantic v2 models.
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install sah-sdk
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
> **GitHub Packages fallback.** Until `sah-sdk` is fully published on PyPI, install directly from the source repository:
|
|
48
|
+
>
|
|
49
|
+
> ```bash
|
|
50
|
+
> pip install "git+https://github.com/Software-Automation-Holdings-LLC/sdk.git@sdk/v0.5.0#subdirectory=packages/python"
|
|
51
|
+
> ```
|
|
52
|
+
>
|
|
53
|
+
> The wire surface is identical either way; only the install command changes.
|
|
54
|
+
|
|
55
|
+
## Quick start
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
import os
|
|
59
|
+
from sah_sdk.zyins import Isa, Applicant, Coverage, PrequalifyInput, Sex
|
|
60
|
+
|
|
61
|
+
# Reads ISA_TOKEN from the environment — no explicit token needed.
|
|
62
|
+
isa = Isa.with_bearer()
|
|
63
|
+
|
|
64
|
+
result = isa.zyins.prequalify(PrequalifyInput(
|
|
65
|
+
applicant=Applicant(
|
|
66
|
+
dob="1962-04-18",
|
|
67
|
+
sex=Sex.MALE,
|
|
68
|
+
height_inches=70,
|
|
69
|
+
weight_pounds=195,
|
|
70
|
+
state="NC",
|
|
71
|
+
nicotine_use="none",
|
|
72
|
+
),
|
|
73
|
+
coverage=Coverage.face_value(100_000),
|
|
74
|
+
products="colonial-penn.final-expense",
|
|
75
|
+
))
|
|
76
|
+
|
|
77
|
+
for plan in result.data.plans:
|
|
78
|
+
print(plan.brand, plan.tier, plan.monthly_premium)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`Isa.with_bearer()` reads `ISA_TOKEN` from the environment. `Authorization: Bearer <token>`,
|
|
82
|
+
`Idempotency-Key`, and the date-pinned `Version` header are set automatically.
|
|
83
|
+
|
|
84
|
+
## First call in <15 lines
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
from sah_sdk.zyins import Isa, Coverage
|
|
88
|
+
|
|
89
|
+
isa = Isa.with_keycode(
|
|
90
|
+
keycode="SDV-HWH-WDD",
|
|
91
|
+
email="john.doe@acme-agency.com",
|
|
92
|
+
)
|
|
93
|
+
result = isa.zyins.prequalify_v2(
|
|
94
|
+
applicant={"dob": "1962-04-18", "sex": "male", "state": "NC"},
|
|
95
|
+
coverage=Coverage.face_value(25_000),
|
|
96
|
+
products="colonial-penn.final-expense",
|
|
97
|
+
)
|
|
98
|
+
print(result.data.plans[0].monthly_premium)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Per-surface API versions
|
|
102
|
+
|
|
103
|
+
The ISA API is a federation of independently versioned surfaces. Every SDK
|
|
104
|
+
release exports a frozen `BUNDLED_API_VERSIONS` mapping recording which
|
|
105
|
+
`/vN` each surface targets:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from sah_sdk.zyins import BUNDLED_API_VERSIONS
|
|
109
|
+
|
|
110
|
+
print(BUNDLED_API_VERSIONS)
|
|
111
|
+
# {
|
|
112
|
+
# "prequalify": "v2",
|
|
113
|
+
# "quote": "v2",
|
|
114
|
+
# "datasets": "v2",
|
|
115
|
+
# "reference": "v2",
|
|
116
|
+
# "sessions": "v1",
|
|
117
|
+
# "branding": "v1",
|
|
118
|
+
# "cases": "v1",
|
|
119
|
+
# }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Pin individual surfaces with a per-surface `api_version` map. There is **no**
|
|
123
|
+
`default` key and **no** string shorthand — resolution is
|
|
124
|
+
`api_version.get(surface, BUNDLED_API_VERSIONS[surface])`:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
isa = await Isa.with_keycode(
|
|
128
|
+
keycode="SDV-HWH-WDD",
|
|
129
|
+
email="john.doe@acme-agency.com",
|
|
130
|
+
api_version={"quote": "v2"}, # pin only quote; everything else bundled
|
|
131
|
+
)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The release that retargets `prequalify` / `quote` / `datasets` / `reference`
|
|
135
|
+
to `v3` will bump those entries. See [SDK syntax proposal §2.7][syntax-27].
|
|
136
|
+
|
|
137
|
+
[syntax-27]: ../../docs/sdk-syntax-proposal.md#27-versioning--per-surface-not-global
|
|
138
|
+
|
|
139
|
+
## Reference data — `.match()`
|
|
140
|
+
|
|
141
|
+
The unversioned `isa.zyins.reference` namespace canonicalizes free-text
|
|
142
|
+
medication and condition input. Unknown text never rejects — it returns a
|
|
143
|
+
structured envelope so the final canonicalization fires server-side at
|
|
144
|
+
`/vN/prequalify`:
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
ds = await isa.zyins.datasets.get(include=["conditions", "medications"])
|
|
148
|
+
|
|
149
|
+
insulin = isa.zyins.medications.match("insulin")
|
|
150
|
+
print(insulin.id, insulin.name, insulin.is_known)
|
|
151
|
+
# med_01KSR2WVAGC05ZGR6FA4QYEB12 INSULIN True
|
|
152
|
+
|
|
153
|
+
# Symmetric traversal — what conditions is insulin used for?
|
|
154
|
+
used_for = insulin.conditions(isa.zyins.reference.Sort.MOST_COMMON_FIRST)
|
|
155
|
+
# frequency-ordered list; cond_01KSR2WVAGC05ZGR6FA4QYEA8X first
|
|
156
|
+
|
|
157
|
+
novel = isa.zyins.medications.match("NewExperimental XR 2026")
|
|
158
|
+
# → {"is_known": False, "input_text": "NewExperimental XR 2026", ...}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`Sort.MOST_COMMON_FIRST` and `Sort.ALPHABETICAL` are the two supported
|
|
162
|
+
orderings.
|
|
163
|
+
|
|
164
|
+
## Case storage — bring your own
|
|
165
|
+
|
|
166
|
+
`isa.zyins.cases.*` routes through a `CaseStorage` adapter. The default is
|
|
167
|
+
the zero-knowledge store — ISA's servers only hold ciphertext and an opaque
|
|
168
|
+
ID. To plug a carrier-controlled store, pass your adapter at construction:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
isa = await Isa.with_keycode(
|
|
172
|
+
keycode=..., email=...,
|
|
173
|
+
case_storage=CarrierCaseStorage(), # optional; default = ZeroKnowledgeCaseStorage
|
|
174
|
+
)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
See [cases guide](https://docs.isaapi.com/docs/cases) for the full
|
|
178
|
+
bring-your-own pattern.
|
|
179
|
+
|
|
180
|
+
## Auth deviation from the TS SDK
|
|
181
|
+
|
|
182
|
+
The TypeScript SDK in this monorepo still carries the pre-#286 HMAC device
|
|
183
|
+
signing surface (`AuthContext` with `licenseKey + orderId + email + deviceId`).
|
|
184
|
+
The Python SDK is built against the post-#286 wire contract: a single
|
|
185
|
+
bearer token (`isa_live_*` / `isa_test_*`) is the entire auth surface.
|
|
186
|
+
This is the intentional simplification called out in the platform's
|
|
187
|
+
`platform_v1_architecture` notes.
|
|
188
|
+
|
|
189
|
+
## Surface
|
|
190
|
+
|
|
191
|
+
| TypeScript | Python |
|
|
192
|
+
| ----------------------------------------- | ----------------------------------- |
|
|
193
|
+
| `client.prequalify(req)` | `client.prequalify.run(input)` |
|
|
194
|
+
| `client.license.activate/deactivate/check`| `client.license.*` (mirrored) |
|
|
195
|
+
| `client.case.email(req)` | `client.case.email(input)` |
|
|
196
|
+
| (new) | `client.quote.run(input)` |
|
|
197
|
+
| (new) | `client.datasets.list/get` |
|
|
198
|
+
| (new) | `client.reference_data.get(kind)` |
|
|
199
|
+
| (new) | `client.usage.summary(period)` |
|
|
200
|
+
|
|
201
|
+
Errors mirror the TS hierarchy: `ISAError` (alias `ZyInsError`, also
|
|
202
|
+
exported as `IsaApiError`) → `LicenseError`, `PrequalifyError`,
|
|
203
|
+
`ValidationError`, `RateLimitError`, `AuthError`,
|
|
204
|
+
`IsaIdempotencyConflictError`.
|
|
205
|
+
|
|
206
|
+
## `Isa` factory client
|
|
207
|
+
|
|
208
|
+
Per [SDK_DESIGN.md §3](https://github.com/Software-Automation-Holdings-LLC/isa-platform/blob/main/docs/SDK_DESIGN.md),
|
|
209
|
+
the recommended entry point is the `Isa` class with three named factories:
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
from sah_sdk.zyins import Isa
|
|
213
|
+
|
|
214
|
+
# Reads ISA_TOKEN from the environment.
|
|
215
|
+
isa = Isa.with_bearer()
|
|
216
|
+
env = isa.zyins.prequalify(req)
|
|
217
|
+
print(env.data, env.request_id, env.idempotency_key, env.retry_attempts)
|
|
218
|
+
|
|
219
|
+
# Or pass the token explicitly.
|
|
220
|
+
isa = Isa.with_bearer("isa_live_…")
|
|
221
|
+
|
|
222
|
+
# License factory — reads ISA_LICENSE_KEYCODE / ISA_LICENSE_EMAIL.
|
|
223
|
+
isa = Isa.with_license()
|
|
224
|
+
|
|
225
|
+
# Session factory — reads ISA_SESSION_ID / ISA_SESSION_SECRET.
|
|
226
|
+
isa = Isa.with_session()
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Each factory raises `IsaConfigError` with a clear, actionable message if
|
|
230
|
+
the required env vars are unset and no explicit arguments are supplied.
|
|
231
|
+
|
|
232
|
+
### Raw HTTP access
|
|
233
|
+
|
|
234
|
+
Every method has a `.with_raw_response()` variant returning both the
|
|
235
|
+
parsed envelope and the underlying HTTP metadata:
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
env, raw = isa.zyins.prequalify.with_raw_response(req)
|
|
239
|
+
raw.status # int
|
|
240
|
+
raw.url # str
|
|
241
|
+
raw.headers # read-only mapping
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Debug logging
|
|
245
|
+
|
|
246
|
+
Set `ISA_LOG=debug` to dump every request and response to **stderr** —
|
|
247
|
+
never stdout, so parent processes piping the consumer's JSON output stay
|
|
248
|
+
clean. Credential headers (`Authorization`, `X-Device-Signature`,
|
|
249
|
+
`X-Session-Signature`) and PII body fields (`email`, `dob`, `ssn`,
|
|
250
|
+
`phone`) are redacted automatically.
|
|
251
|
+
|
|
252
|
+
### Idempotency conflicts
|
|
253
|
+
|
|
254
|
+
When the same `Idempotency-Key` is replayed with a different body the
|
|
255
|
+
server returns 409 `idempotency_conflict`. The SDK raises
|
|
256
|
+
`IsaIdempotencyConflictError` with `.key` and `.first_seen_at` so the
|
|
257
|
+
caller can audit the queued-write bug class:
|
|
258
|
+
|
|
259
|
+
```python
|
|
260
|
+
from sah_sdk.zyins import IsaIdempotencyConflictError
|
|
261
|
+
|
|
262
|
+
try:
|
|
263
|
+
isa.zyins.prequalify(req, idempotency_key="case-42")
|
|
264
|
+
except IsaIdempotencyConflictError as e:
|
|
265
|
+
log.error("key %s first seen at %s", e.key, e.first_seen_at)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Concurrency
|
|
269
|
+
|
|
270
|
+
The `Isa` client is safe for use with `asyncio.gather` and
|
|
271
|
+
`concurrent.futures` — every request mints a fresh request-id and
|
|
272
|
+
idempotency key, and shared client state (auth, base URL, debug logger)
|
|
273
|
+
is read-only after construction. Reuse a single `Isa` instance across
|
|
274
|
+
all concurrent requests; the underlying HTTP transport pools connections
|
|
275
|
+
for you.
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
import asyncio
|
|
279
|
+
from sah_sdk.zyins import Isa
|
|
280
|
+
|
|
281
|
+
isa = Isa.with_bearer()
|
|
282
|
+
|
|
283
|
+
async def one(req):
|
|
284
|
+
return isa.zyins.prequalify(req)
|
|
285
|
+
|
|
286
|
+
results = await asyncio.gather(*(one(r) for r in batch))
|
|
287
|
+
# Each result.request_id is distinct.
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Development
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
hatch run test # pytest
|
|
294
|
+
hatch run lint # ruff + mypy --strict
|
|
295
|
+
hatch build # wheel + sdist
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Live-integration tests run only when `ZYINS_TEST_TOKEN` is set:
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
ZYINS_TEST_TOKEN=isa_test_... hatch run test -- -m integration
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Licenses and Ready
|
|
305
|
+
|
|
306
|
+
The Python SDK exposes the public BPP license-lifecycle surface and the
|
|
307
|
+
platform readiness probe on every `ZyInsClient`:
|
|
308
|
+
|
|
309
|
+
```python
|
|
310
|
+
from sah_sdk.zyins import LicenseCheckInput, ZyInsClient
|
|
311
|
+
|
|
312
|
+
client = ZyInsClient("isa_live_...")
|
|
313
|
+
|
|
314
|
+
result = client.license.check(
|
|
315
|
+
LicenseCheckInput(
|
|
316
|
+
email="john.doe@acme-agency.com",
|
|
317
|
+
keycode="ABC-123-XYZ",
|
|
318
|
+
device_id="dev_01HZK2N5GQR9T8X4B6FJW3Y1AS",
|
|
319
|
+
)
|
|
320
|
+
)
|
|
321
|
+
# result.status: "valid" | "invalid" | "inactive"
|
|
322
|
+
|
|
323
|
+
ready = client.health.get_readiness()
|
|
324
|
+
# ready.ready: True on every required probe = "serving"
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
The pre-existing `client.license` (singular) sub-client targets the
|
|
328
|
+
authenticated `/v1/license/*` self-status endpoints and is untouched.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
isa_sdk/__init__.py,sha256=NF_h4I2dLZoZlA8_-Ns4SIfINgtaSCeRyCRoIppXhxI,1817
|
|
2
|
+
isa_sdk/account.py,sha256=gBpA-w-3we2n5RtCdIRdlgU9efXQF-KtFCXjZSZpIsg,145
|
|
3
|
+
isa_sdk/catalog.py,sha256=pUHgV45njc_SLLOZMb8JzOwHTxyuT48tXFVq4QR12Wo,145
|
|
4
|
+
isa_sdk/core.py,sha256=qyJnqgW4umV7vzWtrkdEH7deh7UCNBe7XYbYOzJP_EU,136
|
|
5
|
+
isa_sdk/proxy.py,sha256=kWTMJCGD0A_8yQewLBF0Kh8dWhCIaQ1H1B2SMVpCuq8,139
|
|
6
|
+
isa_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
isa_sdk/rapidsign.py,sha256=62OZZ-DW4M8YpcOt2pHRJ-DowWrS0r06jGW95cQr7xg,151
|
|
8
|
+
isa_sdk/webhooks.py,sha256=MssU0sHdk0yyJrzMvil_LciDMRobcA5TkflTPE_A8Fs,148
|
|
9
|
+
isa_sdk/zyins.py,sha256=WDPGFM86sZlVeFzHoLNmyi9V6aUvRcw6M5eWAD8fkaQ,1052
|
|
10
|
+
sah_sdk/__contract__.py,sha256=R8DiukLXwZdVbcS97dK1pKDTiJJNynWy3TamN-51wyg,11810
|
|
11
|
+
sah_sdk/__init__.py,sha256=tev0wsnZ7OSh2sTWrxL_cPU-EzXgUV5w9ZO-2YueY18,3431
|
|
12
|
+
sah_sdk/isa.py,sha256=75NTfKXaB5OttGWTf7LMQpgKAxAMbnp_kvwlRSmsxTQ,61928
|
|
13
|
+
sah_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
sah_sdk/webhooks.py,sha256=i5SWFlObiEIzOgp5rfCjoH8waMQLHhRxvbsqwdPMYNQ,864
|
|
15
|
+
sah_sdk/_codemod/__init__.py,sha256=RpZlbHyFQRJpPI_8BUtClILMiWAzD_ENDbBdYH7e1jI,884
|
|
16
|
+
sah_sdk/_codemod/__main__.py,sha256=h6YqcMHNkColGbk4YnA5YjhTP-cwPjSQHYJQZGaaDKg,1302
|
|
17
|
+
sah_sdk/_codemod/rewriter.py,sha256=wGOTR__KGEPYkMt2FlBhNEZpd6gge7ZSd3HNjCoXxgQ,6586
|
|
18
|
+
sah_sdk/account/__init__.py,sha256=9N-4ZHSToefQnEBVYrQdauHcTYVYTUV-c5tyQIcJgmY,4073
|
|
19
|
+
sah_sdk/account/_op.py,sha256=V_4NzwBYCtKdz6Vf0Mx1jnHAewO-99VTptfLTux4xT8,2674
|
|
20
|
+
sah_sdk/account/branding.py,sha256=M-8nsTfP9CGodD7NTYG1K92IJmvGZNs6buUN4kmoqSw,3241
|
|
21
|
+
sah_sdk/account/cases.py,sha256=zvS35CSLEDWjYmkBkJ0dnScqQ6JRKGi_5ciHt1NwPv8,5411
|
|
22
|
+
sah_sdk/account/email.py,sha256=C0w8KIXWEMTvfXOIm-Ce8gMzLCkf0yW6_k8dFUfWW4I,3001
|
|
23
|
+
sah_sdk/account/preferences.py,sha256=8vFiMKUxF5pMdo7k0Bsacv7MuOxAGLQfZVkbGtje-1s,3129
|
|
24
|
+
sah_sdk/account/reference_data.py,sha256=aJ0MszcpjoUDA8DfnNggScKGEfb_mY190jdTbUlqIIo,3823
|
|
25
|
+
sah_sdk/catalog/__init__.py,sha256=xhSsBMcmMJmqgTpe9hZ4uNp7QpfKoCWXkNnCMDuPd04,1017
|
|
26
|
+
sah_sdk/catalog/carriers.py,sha256=--c4VYHnznF7w7YJOBUXG04aXY5CvnEz7xQNmMfI4Z8,13086
|
|
27
|
+
sah_sdk/catalog/conditions.py,sha256=qJYnUCngM2OrBracfQXBskkBADID5JpBlf0nf4ihO9I,1278
|
|
28
|
+
sah_sdk/catalog/errors.py,sha256=-6Lcf-ew91KcXyrzeHfJEmB97K60m-vrk6gN7HC6ENk,4017
|
|
29
|
+
sah_sdk/catalog/medications.py,sha256=2wTNm0dU3gSWBijijwQBSE8MwqF8lgpEG4BY8buUv3c,5131428
|
|
30
|
+
sah_sdk/catalog/products.py,sha256=s6oz2vCtSvg2oV1Q6m0njKgSn-kggw6QpzTQ6Kt1rgg,37663
|
|
31
|
+
sah_sdk/catalog/scopes.py,sha256=RqF3gHYOC_l8lcfqM4ASVTOGu9mEihfoJljAXIS89j0,1224
|
|
32
|
+
sah_sdk/catalog/sign_events.py,sha256=K9TPzHn0AdpjuMgoHuh7_2aXXFMjgctQnlt8jfbZSrE,599
|
|
33
|
+
sah_sdk/catalog/states.py,sha256=xsvmPKOl9evFt20qFbDAV19MsQqDZnwQRHNDPoYbG80,8839
|
|
34
|
+
sah_sdk/core/__init__.py,sha256=921k2f8LGo5bZG7ApMwKClqgK83YDHNE9P0leZpTgaU,1467
|
|
35
|
+
sah_sdk/core/auth.py,sha256=Y5H7oyggPTuaNORcI4fRXfPp_XFUyX_a9mL-RB8BBoI,3441
|
|
36
|
+
sah_sdk/core/bootstrap.py,sha256=ITMf_NJZr32iB8UjwdbWTgjuuJmHA0SDbLKRUAjg_0I,4849
|
|
37
|
+
sah_sdk/core/constants.py,sha256=defSzK9_QKnRrBGMS_1jaDE4H4MKpYRXEQ8P-nYpHbA,2967
|
|
38
|
+
sah_sdk/core/credential_store.py,sha256=xnZ9un3a4Het7HOZ67EaQJSNT-WDIA0J5yny18cxUgU,2941
|
|
39
|
+
sah_sdk/core/debug.py,sha256=oxwgsC3CGtvhVGUQ7WwAmqus-zC3JweAmimDsIllofE,4986
|
|
40
|
+
sah_sdk/core/env.py,sha256=c-fqP1B__l4gJ0r0jDSD75gL8dvyb03iz-msgja1qS8,2260
|
|
41
|
+
sah_sdk/core/envelope.py,sha256=_GTmJCli8DcFkNUvJVwUqZ2VodM1hn81-M5lTcVh6vM,2747
|
|
42
|
+
sah_sdk/core/errors.py,sha256=c4OMmG-5EXAjSDINBgrLaVSmn16YVCw0qi6AD0C4ycw,11935
|
|
43
|
+
sah_sdk/core/idempotency.py,sha256=EmlYl-n5VvQIRDdxig-4Ng2u7aBRC_NNl_Fq4d34H10,491
|
|
44
|
+
sah_sdk/core/json_response.py,sha256=7MErT5GjWfN3OGFsgxQwjxyt_aS_tWawXaS9Fpwe22s,1282
|
|
45
|
+
sah_sdk/core/license_hmac.py,sha256=VfYriveC_DcQcRQ_XpUqdgSLXiSI6l0GtEbCZ9WPpFY,4578
|
|
46
|
+
sah_sdk/core/session.py,sha256=PvxzQRRBR8BQIOD2TRn1AuAoDqnSEeh14tiI54yFqkU,11790
|
|
47
|
+
sah_sdk/core/sign_request.py,sha256=9ybfrWfhbNzI-dwuZDZNRF279fUA-8xDmPxIW3qDFF8,4043
|
|
48
|
+
sah_sdk/core/transport.py,sha256=n5xj_sd3dCbX1Upn5r8ofP2IavKSw3mQHQvRF_4O0jo,2727
|
|
49
|
+
sah_sdk/core/value_types.py,sha256=DPJOrPYtMzjZwo9CHI8z0xvYoeg_V3mDVAxD5I6yHUU,3275
|
|
50
|
+
sah_sdk/core/wire.py,sha256=kF-d3s8mN7z7S1xGq0Rg1ffYex_x0TV2eZkbeReuHHQ,2455
|
|
51
|
+
sah_sdk/proxy/__init__.py,sha256=FPp5YAFPTPLWWl9X3p6_b8gB67qlrwA6LsRfIE1AAbI,2769
|
|
52
|
+
sah_sdk/proxy/call.py,sha256=nImkj8TDj_ndF7GzfAa-lyFnBtt7KucPwk9aeMseJQg,9718
|
|
53
|
+
sah_sdk/rapidsign/__init__.py,sha256=CRRBS_5R-Aj8VscF1dZy0aRyJiGcWX74roUzznc9ojM,910
|
|
54
|
+
sah_sdk/zyins/__init__.py,sha256=DwJkBe5xZyXLD38M8Hl66vdOGWHbisg_XxnQismEEvw,5663
|
|
55
|
+
sah_sdk/zyins/account_namespaces.py,sha256=8rJxN5v7TwRI5CZZi-c5kGHZHBVwBeFODRIVCiCRs5g,4746
|
|
56
|
+
sah_sdk/zyins/applicant.py,sha256=OPsJapMb2xsJ8UWi0Eih8lh6K9ocuYgQMZo8w4Tn86E,6226
|
|
57
|
+
sah_sdk/zyins/branding.py,sha256=m9KTk6mdrGRXOH6m3ybr1mOaVRB7kTjqHC6crm_AGUI,2625
|
|
58
|
+
sah_sdk/zyins/bundled_api_versions.py,sha256=_NXMwLoxWphEmZyaX_uC6Db8jRISdefHObXi7htcfl0,2570
|
|
59
|
+
sah_sdk/zyins/cases.py,sha256=QC7nNqUN5LVA2Q16IEBs_Tqf6BlVvs5D_x33CCDqf6o,4393
|
|
60
|
+
sah_sdk/zyins/cases_storage.py,sha256=_Q483KFhxpDrK5XQi4fAw_DUlYfIs2PBSPOC1D20skg,731
|
|
61
|
+
sah_sdk/zyins/client.py,sha256=fmKCx2X7lQb9dbeXprnkQaFCaOSxV87PDrPRErcd_X8,14069
|
|
62
|
+
sah_sdk/zyins/coverage.py,sha256=4O37-KvAbYexW1c4CewtP-L2EP-Fp1mGsCmyuc1DxC8,3773
|
|
63
|
+
sah_sdk/zyins/credential_state.py,sha256=qrytgrpmut5GI8bFnAqNSbOLudB4h7NCg7VmZKsh9yg,5366
|
|
64
|
+
sah_sdk/zyins/datasets.py,sha256=DM611kkI1hRTEka8LrUixiHoPAvoVdwsH_K3YMe5x0M,1026
|
|
65
|
+
sah_sdk/zyins/datasets_v3.py,sha256=ejTzqieOqiaFHsJGFdqkOk4hgUeseWh6Bwl6gCxJFJQ,29132
|
|
66
|
+
sah_sdk/zyins/health.py,sha256=G2xgT0wE0d-VcQGxHyQ-DcUKolKx-OOvANnB6dLEBTQ,1345
|
|
67
|
+
sah_sdk/zyins/isa_options.py,sha256=gQZoolTOrEk-4lGnFYGbqtsjbvgt1trnp29unizq9v4,10724
|
|
68
|
+
sah_sdk/zyins/license.py,sha256=rM-67Y6MrNm8XZsJSYuZR-JP_m0d3jMuwiYsuNTIsZ4,1442
|
|
69
|
+
sah_sdk/zyins/licenses.py,sha256=Iry9lTWHBCos3cy0wTS7m8bx7fTokrcOgGUEMm9l9HE,3691
|
|
70
|
+
sah_sdk/zyins/licenses_facade.py,sha256=3KGdlef-fkWxwRbgTYXgyxjT-SjPRYnWwDjmD0aaUNg,8147
|
|
71
|
+
sah_sdk/zyins/logos.py,sha256=ZZyopkSUVRt3vnFCSY6VJyiku8aYfnuWflyBmd7wcC4,5061
|
|
72
|
+
sah_sdk/zyins/measurements.py,sha256=IxgfaTYWpC1QeDl6uW8gOYTViXFqTRrh12gy3Wak_Ho,10183
|
|
73
|
+
sah_sdk/zyins/plan_info_label.py,sha256=pSUCrXSwUbPJI9gQA5nDnhtveL6hVMkVhPDQVYcku1E,4641
|
|
74
|
+
sah_sdk/zyins/preferences.py,sha256=WTfM2ewulo_fjej3SojFNrZrdxjS8WiQT6DO9z94hug,2142
|
|
75
|
+
sah_sdk/zyins/prequalify.py,sha256=SRnk925h38h9T9Vi9ZEgnnmv3Zp6P_CWoC7GypSOdL8,9870
|
|
76
|
+
sah_sdk/zyins/prequalify_legacy_blob.py,sha256=NWIsV3rqLDSYloj0JHzikfDLucgz0JRA54ZzmqvBkBA,1733
|
|
77
|
+
sah_sdk/zyins/prequalify_v3.py,sha256=d1Lf1XQa8kLEGeq9zocLC_QurXyOZMpDtB4mZ_3oaqQ,32942
|
|
78
|
+
sah_sdk/zyins/product.py,sha256=lRI3e9FdTeSKfOa7RBVpOjjn0V7DyNYzivrrfpuzPVY,7476
|
|
79
|
+
sah_sdk/zyins/products.py,sha256=8px-1KrlXQIAd1l8Hse39zCuAzlHwTkD-SJkGBOSk0Q,1889
|
|
80
|
+
sah_sdk/zyins/quote.py,sha256=X494k12h1SBUh1xhU_GxXHXMWdSUKF87KCtCM0AkwcM,2473
|
|
81
|
+
sah_sdk/zyins/quote_v3.py,sha256=hmCnWfEaf0AJiMtaA4rYKnGFEbiqPQxJ3l8Caga6c1M,4835
|
|
82
|
+
sah_sdk/zyins/reference_data.py,sha256=1Op-OecASwKT8DoI6fvGiiZgflbBVh3QcRe1UcEjitY,1227
|
|
83
|
+
sah_sdk/zyins/reference_v3.py,sha256=_Y2dGY1Fj7p-SVXtbSrXKgZEJLRZiMqZVLvErcUXYgY,13863
|
|
84
|
+
sah_sdk/zyins/usage.py,sha256=2HWGXt_7d3w2Ca4Ays7AXDiOxI0X-lBaUeJmG9C9hbs,1042
|
|
85
|
+
sah_sdk/zyins/cases/__init__.py,sha256=Z2Ywv7LTpiBC-lYpDoD_pPNbQOwgIWdqOdzWxyDb6RU,8846
|
|
86
|
+
sah_sdk/zyins/cases/storage.py,sha256=lAcH9BxJiE7YDkRkV0MMWX_Db8kp1KM-hYB4v6rD3-4,3897
|
|
87
|
+
sah_sdk/zyins/cases/zero_knowledge.py,sha256=sqKvkhgppjUClQpy-v5U-fVuqCb5gR558SHeFFKeUBw,9646
|
|
88
|
+
sah_sdk/zyins/reference/__init__.py,sha256=49frt652UAuCm9zCBD7mhDVT9yYF7C4lSz9vQ1YaLh0,16342
|
|
89
|
+
sah_sdk/zyins/reference/_make_key.py,sha256=DKrY9TBvTaE-u48r7cqSBTuQ_KoKJkOyDZZKlU-wpmQ,1346
|
|
90
|
+
sah_sdk/zyins/reference/autocomplete_algorithm.py,sha256=b7ei4bAMo8Odxb-BNGmzEBTgrUzVxCDQN7RchI1q50Q,15784
|
|
91
|
+
sah_sdk/zyins/reference/autocorrector.py,sha256=0k5sR4dp5D_nev5vorLCM7r3zBdcXNU5xtVxrFcAC-E,12440
|
|
92
|
+
sah_sdk/zyins/reference/concept.py,sha256=JBGZM0wt8o1sFjzjKW3QPgi7NRI-38AGNHQo3mTq82M,6071
|
|
93
|
+
sah_sdk/zyins/reference/index.py,sha256=4TK0dmSmLeDmOoDHYSos1fMzWeby7QUMSgtg4_PtH4s,10234
|
|
94
|
+
sah_sdk/zyins/reference/match_algorithm.py,sha256=d3DkWEIPsKNlCSQ5RV9O_TEQHNEAaOCjuiqdPqUVu6s,3545
|
|
95
|
+
sah_sdk/zyins/reference/reference_index.py,sha256=CI8xFmY3n8z8f3qHLubgpFpKM_sc3sUihKEhoLR7aSM,9012
|
|
96
|
+
sah_sdk/zyins/reference/sort.py,sha256=22Ll3PvbFcT7MjMXI-SWLKVPDN0ceZE1tOgeKUnLM2c,937
|
|
97
|
+
sah_sdk/zyins/reference/suggestion.py,sha256=8j7Ij6iGLRojFJnKAhhLVJpW767Rv9wH2pY8P27ycfw,2375
|
|
98
|
+
isa_sdk-1.0.0.dist-info/METADATA,sha256=Y_LkVDI0nIwb9aP3TOfVs-ta6k8bTYf02G3rLeFXYzg,10771
|
|
99
|
+
isa_sdk-1.0.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
100
|
+
isa_sdk-1.0.0.dist-info/RECORD,,
|