Metadata-Version: 2.4
Name: wedge-health
Version: 0.3.0
Summary: Python SDK for the authenticated Wedge Health clinical automation API
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: google-auth<3,>=2.29
Requires-Dist: requests<3,>=2.31

# Wedge Health Python SDK

The supported application interface is intentionally small. Select the eCW
health system by its friendly connection label, then call actions on that
scoped object:

```python
import os

from wedge import Wedge

client = Wedge(api_key=os.environ["WEDGE_API_KEY"])
opsam = client.ecw.use("opsam-production")

response = opsam.read_patient(
    patient_id="YOUR_PATIENT_ID",
    id_type="mrn",
)
```

The older `from wedge_api_client import WedgeApiClient` import remains
available for compatibility.

The SDK provides a small, typed interface to the authenticated Wedge Health
clinical automation API. Access is provisioned only to approved callers. The
normal client sends one `X-Wedge-API-Key` to the Wedge access broker. It does
not use Google Application Default Credentials, mint JWTs, or give callers any
Google Cloud access. Request and response bodies, patient identifiers, API
keys, and eCW credentials are never logged. The client performs no automatic
HTTP retries.

The one-key staging broker is live at
`https://wedge-api-staging-access-vl5zuw7zfa-wl.a.run.app`, which is the SDK's
fixed default. Connection inventory is deployment-specific. A clinical call
becomes usable only after an administrator creates the selected connection and
grants the calling key its label and exact action.

Infrastructure authorization is not operational approval. Writes and durable
exports must not be invoked without action-specific approval and the required
idempotency controls.

## Install

Python 3.11 or newer is required. The canonical distribution name is
`wedge-health`:

```console
python3 -m pip install wedge-health
```

The `wedge-ai` distribution is a compatibility installer. It contains no
import packages and depends on the matching `wedge-health` release, so either
installation name provides the same supported import:

```python
from wedge import Wedge
```

Prefer `wedge-health` in new dependency files and documentation. From this
repository checkout:

```console
python3 -m venv .venv-wedge-api
./.venv-wedge-api/bin/python -m pip install --upgrade pip
./.venv-wedge-api/bin/python -m pip install -e ./clients/python
```

From another private Git repository, pin the dependency to a reviewed commit
instead of a moving branch:

```text
wedge-health @ git+https://github.com/wedge-health/wedge-api.git@REVIEWED_COMMIT_SHA#subdirectory=clients/python
```

The package uses `requests>=2.31,<3`. It temporarily retains
`google-auth>=2.29,<3` only for the explicitly enabled legacy transport; normal
one-key callers do not initialize it.

## Configure approved access

Set the restricted key supplied by a Wedge API administrator in the process
environment:

```console
export WEDGE_API_KEY="..."
```

No base-URL setting is required: the SDK uses the live staging broker shown
above. Normal callers do not install or run `gcloud`, configure Application
Default Credentials, or receive access to Wedge's Google Cloud project.

Never put credentials in source code, committed environment files, command-line
arguments, logs, tickets, or documentation.

## Create an eCW connection once

An administrator supplies credentials once during onboarding. They are sent
over HTTPS to the broker, validated, and stored by the managed backend. They
are not retained by the returned Python object:

```python
import os

from wedge import Wedge

client = Wedge(api_key=os.environ["WEDGE_API_KEY"])
opsam = client.ecw.connect(
    label="opsam-production",
    url=os.environ["OPSAM_ECW_URL"],
    username=os.environ["OPSAM_ECW_USERNAME"],
    password=os.environ["OPSAM_ECW_PASSWORD"],
    two_factor_method="email",
    email_username=os.environ["OPSAM_ECW_EMAIL_USERNAME"],
    email_password=os.environ["OPSAM_ECW_EMAIL_PASSWORD"],
)
```

Creation is durable before the first browser warm-up. If `opsam.status` is
`"reauthentication_required"`, keep the returned scoped object and retry
`client.ecw.warm("opsam-production")` after resolving login or 2FA. Do not
resubmit the same label as a new connection.

The returned scoped object exposes only its stable friendly label and initial
status. Internal connection identifiers stay behind the API boundary. Normal
requests route by `opsam-production`.

For authenticator-based 2FA, use `two_factor_method="authenticator"` and pass
`totp_secret=` instead of either email field. The two modes cannot be mixed.

## Read one patient

Assign the identifier supplied by the calling application's approved workflow:

```python
import os

from wedge import Wedge

client = Wedge(api_key=os.environ["WEDGE_API_KEY"])
opsam = client.ecw.use("opsam-production")

response = opsam.read_patient(
    patient_id="YOUR_PATIENT_ID",
    id_type="mrn",
)
```

An application key can use only the connection labels and exact actions its
administrator assigned. Guessing another customer's label returns the same
generic not-found response as a nonexistent label. Reuse one client instance
and call `client.close()` during shutdown.

## Call another action

Use the human-readable [`API_REFERENCE.md`](../../API_REFERENCE.md). Every
reviewed action has its purpose, complete input table, defaults, constraints,
permission, idempotency rules, response guidance, and a safe Python example.
You do not need to read the raw OpenAPI JSON to use the SDK.

Every reviewed action has a direct, keyword-only method on the selected
connection. Unknown parameters and positional misuse fail closed before an HTTP
request. For an action whose contract requires idempotency, generate and
durably retain one canonical UUID and pass it as `operation_id`. The method
automatically sends the same value as `Idempotency-Key`; an explicitly supplied
`idempotency_key` must match. Reuse that value only to reconcile the same
unknown outcome.

```python
operation_id = "YOUR_OPERATION_UUID"

result = opsam.retrieve_document(
    patient_id="YOUR_PATIENT_ID",
    id_type="mrn",
    document_type="registration",
    operation_id=operation_id,
)
```

## Safe errors

All public exceptions derive from `WedgeApiError`. HTTP failures expose only
`status_code` and a sanitized `request_id`; response bodies, credentials, and
request bodies are never included:

```python
from wedge import WedgeApiError

try:
    result = opsam.lookup_schedule(
        date="YOUR_APPOINTMENT_DATE",
        resource_id="YOUR_RESOURCE_ID",
    )
except WedgeApiError as error:
    status_code = error.status_code
    request_id = error.request_id
```

Logging those two fields is safe. Do not log the request, response, exception
locals, client instance, or environment.

## Multiple health systems and limited application keys

An administrator can own many named connections and call reviewed actions on
any ACTIVE connection it owns, while issuing a regular key
that can see only one of them:

```python
opsam_key = client.api_keys.create(
    label="opsam-application",
    connections=["opsam-production"],
    actions=["read_patient", "retrieve_document"],
)
```

The returned application key cannot list, select, or call the administrator's
other connections. Regular application keys cannot create, rotate, or disable
connections.

An administrator can inspect all owned labels without retrieving credential
secrets:

```python
inventory = client.ecw.connections.list_admin()
```

The returned value is a normal dictionary:

```python
{
    "connections": [
        {
            "label": "opsam-production",
            "status": "active",
            "credentials": {
                "ecw_hostname": "practice.ecwcloud.com",
                "username_masked": "o****r",
                "two_factor_method": "email",
                "credentials_updated_at": "2026-07-25T22:00:00Z",
            },
        },
        {"label": "legacy-production", "status": "disabled", "credentials": None},
    ]
}
```

Each entry includes `label`, `status`, and either `credentials=None` for a
legacy record or safe metadata containing `ecw_hostname`, a fixed-shape
`username_masked`, `two_factor_method`, and `credentials_updated_at`. The
timestamp reflects creation or credential rotation, not session warm-up.
Complete usernames, passwords, email credentials, TOTP secrets, internal
connection IDs, and secret references are never returned. Application keys
cannot call `list_admin()`; their normal `list()` method still returns only
assigned labels and statuses.

Credential rotation supplies a complete replacement bundle, including the eCW
URL:

```python
client.ecw.rotate_credentials(
    "opsam-production",
    url=os.environ["OPSAM_ECW_URL"],
    username=os.environ["OPSAM_ECW_USERNAME"],
    password=os.environ["OPSAM_ECW_PASSWORD"],
    two_factor_method="authenticator",
    totp_secret=os.environ["OPSAM_ECW_TOTP_SECRET"],
)
```

The previous secret version is not modified, and neither version is returned
by the API.

## Legacy direct-Gateway mode

The old Google API Gateway transport remains temporarily available only when
code explicitly passes `legacy_dual_auth=True`. It may use Google ADC and is
not the supported public API experience. New applications should not enable
it.

## Run tests

Tests use injected fake HTTP sessions and never contact Google, the Gateway, or
either clinical portal:

```console
cd clients/python
../../.venv-wedge-api/bin/python -m unittest discover -s tests -v
```
