Skip to main content

Official Python client for the Medsplain TX medical text simplification API

Project description

Medsplain TX — Python SDK

Official Python client for the Medsplain TX medical text simplification API. Send clinical / medical text and get back a plain-language explanation.

The SDK ships three clients, one per credential type:

Client Credential Use it to…
Medsplain mds_live_… API key (x-api-key) Simplify medical text (translate, health check).
OrganizationClient mds_org_secret_… secret key (org admin) Manage your organization and its API keys.
AdminClient Cognito JWT access token (Authorization: Bearer) Platform admin: organizations, payments, admins, config.

Installation

pip install medsplain

Until this is published to PyPI, install from source — see Local development.

Quick start

from medsplain import Medsplain

client = Medsplain(api_key="mds_live_...")

result = client.translate("Patient presents with acute myocardial infarction.")
print(result.simplified_text)
print(f"{result.source_chars} chars in, {result.output_chars} chars out")

The client is a context manager, which closes the connection pool for you:

with Medsplain(api_key="mds_live_...") as client:
    result = client.translate("CBC shows leukocytosis with left shift.")
    print(result.simplified_text)

Configuration

Argument Env var Default Notes
api_key MEDSPLAIN_API_KEY Required. Your mds_live_ key.
base_url MEDSPLAIN_BASE_URL http://localhost:8000 API root, without the /v1 prefix.
timeout 30.0 Per-request timeout in seconds.
max_retries 2 Retries on connection errors, 429, and 5xx.
import os
client = Medsplain(
    api_key=os.environ["MEDSPLAIN_API_KEY"],
    base_url="https://your-medsplain-host.example.com",
    timeout=60.0,
)

API

translate(text, *, model=None) -> TranslationResult

Simplify medical text into plain language. text must be non-empty and at most 5000 characters.

Automatically retries against a secondary backend if the primary is unreachable, erroring server-side, or rate-limited — no configuration needed. Errors that would fail identically against either backend (bad input, an invalid key, no active plan) are raised immediately without a fallback attempt.

health_check() -> HealthStatus

Verify the API is reachable (GET /health-check).

TranslationResult

Field Type Description
original_text str Cleaned input text the server processed.
simplified_text str The plain-language simplification.
source_chars int Character count of the input.
output_chars int Character count of the output.
is_medical_text bool Whether the input was detected as medical.
is_conversation bool Whether the input was detected as conversational.
raw dict Full, unmodified response payload.

Error handling

Every error inherits from MedsplainError. HTTP failures raise an APIStatusError subclass chosen by status code:

from medsplain import (
    Medsplain, AuthenticationError, RateLimitError,
    PermissionDeniedError, APIStatusError,
)

client = Medsplain(api_key="mds_live_...")
try:
    result = client.translate("...")
except AuthenticationError:
    ...                       # 401 — key missing/invalid/expired/revoked
except RateLimitError as e:
    print("retry after", e.retry_after)   # 429 — rate limit or token quota
except PermissionDeniedError:
    ...                       # 403 — no active plan / subscription
except APIStatusError as e:
    print(e.status_code, e.code, e.message)
Exception Status Meaning
BadRequestError 400 Malformed request / validation error.
AuthenticationError 401 API key missing, invalid, expired, or revoked.
PermissionDeniedError 403 No active plan or subscription.
NotFoundError 404 Resource not found.
RateLimitError 429 Rate limit hit or token quota exhausted.
ServerError 5xx Server-side failure.
APIConnectionError The request never reached the server.

Organization management

OrganizationClient manages your organization and the API keys your applications use. It authenticates with your organization secret key (mds_org_secret_…) — a different credential from the mds_live_ key above — sent in the X-Organization-Secret-Key header.

from medsplain import OrganizationClient

with OrganizationClient(
    org_id="org_000000000001",
    secret_key="mds_org_secret_...",
) as org:
    # Inspect the organization
    info = org.get_organization()
    print(info.plan_type, info.total_tokens_used)

    # Create a key — the full mds_live_ value is returned ONLY here
    created = org.create_api_key(name="production", description="prod server")
    print(created.api_key)          # store this securely; never shown again

    # List, fetch, disable, delete
    keys = org.list_api_keys(is_active=True)
    one = org.get_api_key(created.id)
    org.set_api_key_status(created.id, is_active=False)
    org.delete_api_key(created.id)

Configuration

Argument Env var Default Notes
org_id MEDSPLAIN_ORG_ID Required. e.g. org_000000000001.
secret_key MEDSPLAIN_ORG_SECRET_KEY Required. Your mds_org_secret_ key.
base_url MEDSPLAIN_BASE_URL http://localhost:8000 API root, without the /v1 prefix.

timeout and max_retries work exactly as on Medsplain. With both env vars set you can construct it with no arguments: OrganizationClient(). (The SDK does not load .env files — export the variables yourself.)

Methods

Method API call Returns
get_organization() GET /v1/admin/organizations/{org_id} Organization
create_api_key(name, *, description=None, expires_at=None) POST …/api-keys ApiKeyWithSecret
list_api_keys(*, is_active=None, limit=50, offset=0) GET …/api-keys ApiKeyList
get_api_key(key_id) GET …/api-keys/{key_id} ApiKey
set_api_key_status(key_id, *, is_active) PATCH …/api-keys/{key_id}/status ApiKey
delete_api_key(key_id) DELETE …/api-keys/{key_id} dict

expires_at accepts a datetime or an ISO-8601 string. Errors map to the same exception hierarchy as Medsplain (e.g. an invalid secret key raises AuthenticationError, an organization with no active plan raises PermissionDeniedError).

Result models

Organizationid, name, owner_email, plan_type, token_limit (int, "Unlimited", or None), total_tokens_used, max_api_keys, api_keys_created, subscription_start_date, subscription_end_date, is_active, created_at, updated_at, raw.

ApiKeyid, organization_id, key_prefix, name, description, total_tokens_used, last_used_at, is_active, expires_at, created_at, raw.

ApiKeyWithSecret — all ApiKey fields plus api_key (the full mds_live_ key, returned only by create_api_key).

ApiKeyListapi_keys (list of ApiKey), total, raw.

Datetime fields are returned as raw ISO-8601 strings (or None), and every model keeps the untouched payload in raw.

Platform administration

AdminClient manages the platform itself — organizations, payments, admin users, and system config. It authenticates with a Cognito JWT access token for an admin user (Authorization: Bearer …). A few operations require super-admin privileges; the server enforces the role and returns 403 (PermissionDeniedError) otherwise.

from medsplain import AdminClient

# Option 1 — log in (calls POST /v1/login)
admin = AdminClient.login("admin@example.com", "password", base_url="https://host")
print(admin.tokens["refresh_token"])     # full Cognito token set is on .tokens

# Option 2 — bring your own token
admin = AdminClient(access_token="eyJ...", base_url="https://host")

with admin:
    # Organizations
    org = admin.create_organization(name="Acme Health", owner_email="ops@acme.com")
    print(org.secret_key)                 # mds_org_secret_... — give this to the org owner
    admin.list_organizations(is_active=True)
    admin.update_organization(org.id, name="Acme Health Inc")
    admin.rotate_organization_secret(org.id)

    # Payments — status="paid" activates the org and applies the plan
    pay = admin.create_payment(org.id, amount=499, currency="usd",
                               status="paid", plan_type="pro")
    admin.list_payments(organization_id=org.id)
    admin.update_payment(org.id, pay.id, status="refunded")

    # Admin users (super-admin) and config
    admin.list_admins()
    admin.create_admin("newadmin@example.com")      # super-admin only
    admin.list_config()
    admin.update_config("rate_limit_api_key_max_requests", "120")  # super-admin only

    admin.delete_organization(org.id)

Configuration

Argument Env var Default Notes
access_token MEDSPLAIN_ADMIN_TOKEN Required. Admin Cognito JWT access token.
base_url MEDSPLAIN_BASE_URL http://localhost:8000 API root, without the /v1 prefix.

AdminClient.login(username, password, *, base_url=…) returns a ready client and stores the full token set (access_token, refresh_token, id_token, is_verified) on .tokens. Cognito access tokens expire and there is no refresh endpoint — log in again (or pass a fresh token) when you get a 401.

Methods

Method API call Role Returns
login(username, password, *, base_url=…) (classmethod) POST /v1/login AdminClient
create_organization(*, name, owner_email) POST /v1/admin/organizations admin OrganizationWithSecret
list_organizations(*, is_active=None, limit=50, offset=0) GET /v1/admin/organizations admin OrganizationList
update_organization(org_id, *, name=None, owner_email=None) PATCH /v1/admin/organizations/{org_id} admin Organization
delete_organization(org_id) DELETE /v1/admin/organizations/{org_id} admin dict
rotate_organization_secret(org_id) POST …/{org_id}/rotate-secret admin RotateSecretResult
create_payment(org_id, *, amount, currency, status, plan_type, …) POST …/{org_id}/payments admin Payment
update_payment(org_id, payment_id, *, status=None, …) PATCH …/{org_id}/payments/{payment_id} admin Payment
list_payments(*, organization_id=None, payment_status=None, limit=50, offset=0) GET /v1/admin/payments admin PaymentList
list_admins(*, limit=50, offset=0) GET /v1/admin/admins admin AdminUserList
create_admin(email) POST /v1/admin/admins super-admin AdminUser
delete_admin(email) DELETE /v1/admin/admins super-admin dict
list_config() GET /v1/admin/config admin ConfigList
update_config(key, value) PATCH /v1/admin/config super-admin ConfigEntry

create_payment accepts statuspending|paid|failed|refunded, plan_typebasic|pro|enterprise, and paid_at as a datetime or ISO-8601 string. The new models (OrganizationWithSecret, OrganizationList, RotateSecretResult, Payment, PaymentList, AdminUser, AdminUserList, ConfigEntry, ConfigList) follow the same dataclass style — raw ISO-8601 datetimes and a raw payload field.

Local development

cd sdk
python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install -e ".[dev]"

pytest                              # run tests
ruff check .                        # lint
mypy src/                           # type-check
python -m build                     # build wheel + sdist into dist/

License

MIT — see LICENSE.

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

medsplain-1.1.1.tar.gz (16.4 kB view details)

Uploaded Source

Built Distribution

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

medsplain-1.1.1-py3-none-any.whl (21.5 kB view details)

Uploaded Python 3

File details

Details for the file medsplain-1.1.1.tar.gz.

File metadata

  • Download URL: medsplain-1.1.1.tar.gz
  • Upload date:
  • Size: 16.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for medsplain-1.1.1.tar.gz
Algorithm Hash digest
SHA256 578ef14472be2dad4014c7f30eaa82ee66923accfbd5430855320d4d33183bd9
MD5 8c1f06a125dac15f49555b6aa90ae029
BLAKE2b-256 21ed4de2a34a715c8e68862964bb59dd12baf3b853a61a7afecb240c9b734be3

See more details on using hashes here.

File details

Details for the file medsplain-1.1.1-py3-none-any.whl.

File metadata

  • Download URL: medsplain-1.1.1-py3-none-any.whl
  • Upload date:
  • Size: 21.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for medsplain-1.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0ed939a2ad9c84654cb9408e11ffadc18fa8b668f345aa62c6ec33f752041cfe
MD5 7e7ad026b130f8eda0c8df3de5341123
BLAKE2b-256 7d3401d726dce99eb6bc85f25c6376a782d911f6ffdd81ced094d842c1618248

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