Unified Python SDK for ISA APIs (zyins, rapidsign, proxy).
Project description
isa-sdk
Python SDK for the Best Plan Pro API — powered by the ZyINS engine. Mirrors the
canonical TypeScript SDK with Python-idiomatic naming (snake_case) and
pydantic v2 models.
Install
pip install isa-sdk
Quick start
from isa_sdk.zyins import (
Isa, Applicant, Coverage, Sex,
NicotineUsageInput, NicotineDuration,
)
from isa_sdk.zyins.prequalify_v3 import PrequalifyV3Request
from isa_sdk.zyins.product import Product, ProductSelection, ProductType
# Reads ISA_TOKEN from the environment — no explicit token needed. The bare
# `isa.zyins.prequalify` facade routes to v3 by default; `prequalify_v3` is
# the explicit, typed entry point. Both resolve to an envelope.
isa = Isa.with_bearer()
result = isa.zyins.prequalify_v3(PrequalifyV3Request(
applicant=Applicant(
dob="1962-04-18",
sex=Sex.MALE,
height_inches=70,
weight_pounds=195,
state="NC",
nicotine_use=NicotineUsageInput(last_used=NicotineDuration.NEVER),
),
coverage=Coverage.face_value(100_000),
products=ProductSelection.of(Product(
brand="aetna-accendo",
type=ProductType.FINAL_EXPENSE,
wire_token="fex",
display_name="Final Expense",
)),
))
for offer in result.data.plans:
headline = next((row for row in offer.pricing if row.primary), None)
premium = headline.premium.amount.display if headline and headline.premium else None
print(offer.carrier.name, offer.product.name, premium)
Isa.with_bearer() reads ISA_TOKEN from the environment. Authorization: Bearer <token>,
Idempotency-Key, and the date-pinned Version header are set automatically.
First call in <15 lines
from isa_sdk.zyins import Isa, Applicant, Coverage, Sex
from isa_sdk.zyins.prequalify_v3 import PrequalifyV3Request, offer_premium
from isa_sdk.zyins.product import Product, ProductSelection, ProductType
isa = Isa.with_keycode(
keycode="ABC-123-XYZ",
email="john.doe@acme-agency.com",
)
result = isa.zyins.prequalify_v3(PrequalifyV3Request(
applicant=Applicant(
dob="1962-04-18", sex=Sex.MALE,
height_inches=70, weight_pounds=195, state="NC",
),
coverage=Coverage.face_value(25_000),
products=ProductSelection.of(Product(
brand="aetna-accendo", type=ProductType.FINAL_EXPENSE,
wire_token="fex", display_name="Final Expense",
)),
))
first = result.data.plans[0]
headline = offer_premium(first)
print(first.carrier.name, headline.amount.display if headline else None)
Per-surface API versions
The ISA API is a federation of independently versioned surfaces. Every SDK
release exports a frozen BUNDLED_API_VERSIONS mapping recording which
/vN each surface targets:
from isa_sdk import BUNDLED_API_VERSIONS
print(BUNDLED_API_VERSIONS)
# {
# "prequalify": "v3",
# "quote": "v3",
# "datasets": "v3",
# "reference": "v3",
# "sessions": "v1",
# "branding": "v1",
# "cases": "v1",
# }
Pin individual surfaces with a per-surface api_version map. There is no
default key and no string shorthand — resolution is
api_version.get(surface, BUNDLED_API_VERSIONS[surface]):
isa = Isa.with_keycode(
keycode="ABC-123-XYZ",
email="john.doe@acme-agency.com",
api_version={"quote": "v2"}, # pin only quote; everything else bundled
)
prequalify / quote / datasets / reference default to v3 — the flat
plans shape, the Money primitive, and the reference adapters all work out of
the box. Pin api_version={"prequalify": "v2"} only when a consumer still
needs the legacy v2 shape. See SDK syntax proposal §2.7.
Reference data — .match()
The unversioned isa.zyins.reference namespace canonicalizes free-text
medication and condition input. Unknown text never rejects — it returns a
structured envelope so the final canonicalization fires server-side at
/vN/prequalify:
The bundleless match lazily builds and caches the reference index on
its first call — no explicit dataset fetch is required.
from isa_sdk.zyins.reference import Sort
insulin = isa.zyins.medications.match("insulin")
print(insulin.id, insulin.name, insulin.is_known)
# med_01KSR2WVAGC05ZGR6FA4QYEB12 INSULIN True
# Symmetric traversal — what conditions is insulin used for?
used_for = insulin.conditions(Sort.MOST_COMMON_FIRST)
# frequency-ordered list; cond_01KSR2WVAGC05ZGR6FA4QYEA8X first
novel = isa.zyins.medications.match("NewExperimental XR 2026")
# → {"is_known": False, "input_text": "NewExperimental XR 2026", ...}
Sort.MOST_COMMON_FIRST and Sort.ALPHABETICAL are the two supported
orderings.
Case storage — bring your own
isa.zyins.cases.* routes through a CaseStorage adapter. The default is
the zero-knowledge store — ISA's servers only hold ciphertext and an opaque
ID. To plug a carrier-controlled store, pass your adapter at construction:
isa = Isa.with_keycode(
keycode=..., email=...,
case_storage=CarrierCaseStorage(), # optional; default = ZeroKnowledgeCaseStorage
)
See cases guide for the full bring-your-own pattern.
Auth deviation from the TS SDK
The TypeScript SDK in this monorepo still carries the pre-#286 HMAC device
signing surface (AuthContext with licenseKey + orderId + email + deviceId).
The Python SDK is built against the post-#286 wire contract: a single
bearer token (isa_live_* / isa_test_*) is the entire auth surface.
This is the intentional simplification called out in the platform's
platform_v1_architecture notes.
Surface
| TypeScript | Python |
|---|---|
client.prequalify(req) |
client.prequalify.run(input) |
client.license.activate/deactivate/check |
client.license.* (mirrored) |
client.case.email(req) |
client.case.email(input) |
| (new) | client.quote.run(input) |
| (new) | client.datasets.list/get |
| (new) | client.reference_data.get(kind) |
| (new) | client.usage.summary(period) |
Errors mirror the TS hierarchy: ISAError (alias ZyInsError, also
exported as IsaApiError) → LicenseError, PrequalifyError,
ValidationError, RateLimitError, AuthError,
IsaIdempotencyConflictError.
Isa factory client
Per SDK_DESIGN.md §3,
the recommended entry point is the Isa class with three named factories:
from isa_sdk.zyins import Isa
# Reads ISA_TOKEN from the environment.
isa = Isa.with_bearer()
env = isa.zyins.prequalify(req)
print(env.data, env.request_id, env.idempotency_key, env.retry_attempts)
# Or pass the token explicitly.
isa = Isa.with_bearer("isa_live_…")
# License factory — reads ISA_LICENSE_KEYCODE / ISA_LICENSE_EMAIL.
isa = Isa.with_license()
# Session factory — reads ISA_SESSION_ID / ISA_SESSION_SECRET.
isa = Isa.with_session()
Each factory raises IsaConfigError with a clear, actionable message if
the required env vars are unset and no explicit arguments are supplied.
Raw HTTP access
Every method has a .with_raw_response() variant returning both the
parsed envelope and the underlying HTTP metadata:
env, raw = isa.zyins.prequalify.with_raw_response(req)
raw.status # int
raw.url # str
raw.headers # read-only mapping
Debug logging
Set ISA_LOG=debug to dump every request and response to stderr —
never stdout, so parent processes piping the consumer's JSON output stay
clean. Credential headers (Authorization, X-Device-Signature,
X-Session-Signature) and PII body fields (email, dob, ssn,
phone) are redacted automatically.
Idempotency conflicts
When the same Idempotency-Key is replayed with a different body the
server returns 409 idempotency_conflict. The SDK raises
IsaIdempotencyConflictError with .key and .first_seen_at so the
caller can audit the queued-write bug class:
from isa_sdk.zyins import IsaIdempotencyConflictError
try:
isa.zyins.prequalify(req, idempotency_key="case-42")
except IsaIdempotencyConflictError as e:
log.error("key %s first seen at %s", e.key, e.first_seen_at)
Concurrency
The Isa client is safe for use with asyncio.gather and
concurrent.futures — every request mints a fresh request-id and
idempotency key, and shared client state (auth, base URL, debug logger)
is read-only after construction. Reuse a single Isa instance across
all concurrent requests; the underlying HTTP transport pools connections
for you.
import asyncio
from isa_sdk.zyins import Isa
isa = Isa.with_bearer()
async def one(req):
return isa.zyins.prequalify(req)
results = await asyncio.gather(*(one(r) for r in batch))
# Each result.request_id is distinct.
Development
hatch run test # pytest
hatch run lint # ruff + mypy --strict
hatch build # wheel + sdist
Live-integration tests run only when ZYINS_TEST_TOKEN is set:
ZYINS_TEST_TOKEN=isa_test_... hatch run test -- -m integration
Licenses and Ready
The Python SDK exposes the public BPP license-lifecycle surface and the
platform readiness probe on every ZyInsClient:
from isa_sdk.zyins import LicenseCheckInput, ZyInsClient
client = ZyInsClient("isa_live_...")
result = client.license.check(
LicenseCheckInput(
email="john.doe@acme-agency.com",
keycode="ABC-123-XYZ",
device_id="dev_01HZK2N5GQR9T8X4B6FJW3Y1AS",
)
)
# result.status: "valid" | "invalid" | "inactive"
ready = client.health.get_readiness()
# ready.ready: True on every required probe = "serving"
The pre-existing client.license (singular) sub-client targets the
authenticated /v1/license/* self-status endpoints and is untouched.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file isa_sdk-1.0.3.tar.gz.
File metadata
- Download URL: isa_sdk-1.0.3.tar.gz
- Upload date:
- Size: 623.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3445902734a799a6b209102b6c50aff637706b4698ee63a92a5bebb3a3c9d9de
|
|
| MD5 |
81b1ab11eec24ebc5816a1f35eb92ac3
|
|
| BLAKE2b-256 |
52ae9dd5f73f3a5f59154a9e5eb5b314534ec6642acd7cffd15d974414164a4b
|
File details
Details for the file isa_sdk-1.0.3-py3-none-any.whl.
File metadata
- Download URL: isa_sdk-1.0.3-py3-none-any.whl
- Upload date:
- Size: 534.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9b217a291bba05d748b9a21fceb7072b2e1a01043e4a7fa2e18cc600f9a453b8
|
|
| MD5 |
aed860d601d79bc2982c87343a9f39d9
|
|
| BLAKE2b-256 |
547d80e8a3d6e55f021912db7308d258c571f5ab07356e553e299cb2dc2d1cf2
|