Skip to main content

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 PrequalifyRequest
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(PrequalifyRequest(
    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 PrequalifyRequest, 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(PrequalifyRequest(
    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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

isa_sdk-1.0.8.tar.gz (644.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

isa_sdk-1.0.8-py3-none-any.whl (551.2 kB view details)

Uploaded Python 3

File details

Details for the file isa_sdk-1.0.8.tar.gz.

File metadata

  • Download URL: isa_sdk-1.0.8.tar.gz
  • Upload date:
  • Size: 644.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for isa_sdk-1.0.8.tar.gz
Algorithm Hash digest
SHA256 59c79032c46e122b6ea72901ff91ea2065553a88993ce541a78e533ddedf3bb0
MD5 90ae99bc8e6bf0c02a9ea7e41cd790d3
BLAKE2b-256 4d9abf8b426a39b221e97b7f70bfacf40762bd7fa61242394369b983211ea2dd

See more details on using hashes here.

File details

Details for the file isa_sdk-1.0.8-py3-none-any.whl.

File metadata

  • Download URL: isa_sdk-1.0.8-py3-none-any.whl
  • Upload date:
  • Size: 551.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for isa_sdk-1.0.8-py3-none-any.whl
Algorithm Hash digest
SHA256 7e8ca26bc95792c46ddd22e81d09de706ffb2aabc24d7082593b057c163f0096
MD5 b6071c01cb420ad12f7d6e4013459ba3
BLAKE2b-256 cfc3b346621ecaea6b8b2819557b57d2162234c64d34da515f038f0d13d97741

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page