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.7.tar.gz (639.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.7-py3-none-any.whl (548.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: isa_sdk-1.0.7.tar.gz
  • Upload date:
  • Size: 639.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.7.tar.gz
Algorithm Hash digest
SHA256 f603c47d71b1c6a1b5330958d774859d16fc1d4cc4eb4eb6699478e9ba21ec70
MD5 badb0a58175baa83cf49d09cc66961a7
BLAKE2b-256 9168fb9af81cf80de7de438c83838704b78b94ceef89ba321c0767cfeef32ff6

See more details on using hashes here.

File details

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

File metadata

  • Download URL: isa_sdk-1.0.7-py3-none-any.whl
  • Upload date:
  • Size: 548.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.7-py3-none-any.whl
Algorithm Hash digest
SHA256 e73a499c7aa82e30c965d93215f85a4880320f1e7130787de1d4445c64c62a31
MD5 a09bdddc03da370625e5342e7002df33
BLAKE2b-256 079edfc7512079703ba4f1d3e7480ee0486cf3617ed42e88aa5b9570015e323c

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