Official Python SDK for the Uphealth Signal API — cued health-message streams with a receptivity score and an audience-safety verdict on every cue.
Project description
uphealth-signal
The official Python SDK for the Uphealth Signal API — cued health-message streams. Create a stream for a patient, then advance it one cue at a time; each cue returns the next federally-sourced message the engine selects, plus an advisory receptivity score and an audience-safety verdict.
- ✅ Fully typed, zero runtime dependencies (standard library only)
- ✅
run_streamhelper drives the create → cue → feedback loop for you - ✅ Typed exceptions (
RateLimitError,ConflictError, …) with structured fields - ✅ Automatic, idempotency-safe retries with backoff
- ✅ Idempotency keys generated for you
- ✅ Forward-compatible: every model keeps a
.rawdict of the original payload
Display mode never touches PHI and needs no BAA. Keep your API key server-side.
Install
pip install uphealth-signal
Get a free Discovery sandbox key (no credit card) at https://uphealth.us/signup, then:
export UPHEALTH_API_KEY=up_sandbox_…
Quickstart
from uphealth_signal import Signal, is_stream_exhausted
signal = Signal() # reads UPHEALTH_API_KEY
stream = signal.streams.create(template_id="general_wellness_daily")
print(stream.first_cue.body) # the opening message
print(stream.first_cue.receptivity) # 0.5 for a brand-new patient
# The one rule: every cue after the first requires feedback on the prior one.
outcome = signal.streams.cue(stream.stream_id, "did_it")
if not is_stream_exhausted(outcome):
print(outcome.next_cue.body)
Run a whole sequence
run_stream creates the stream and loops the cue/feedback contract until it ends, so you can't trip 409 feedback_required:
def decide(cue, index, stream_id):
return "will_try" if cue.kind == "tip" else "acknowledge"
run = signal.streams.run_stream(decide, template_id="general_wellness_daily", max_cues=50)
print(len(run.transcript), "cues; ended:", run.ended_reason)
The decider returns a response-action string or a dict of cue() keyword arguments.
Configuration
signal = Signal(
api_key="up_sandbox_…", # or the UPHEALTH_API_KEY env var
base_url="https://api.uphealth.us/v1/signal", # default
timeout=30.0, # seconds
max_retries=2, # 5xx + network retries for idempotent calls
default_headers={},
)
The four endpoints
| Call | Endpoint |
|---|---|
signal.streams.create(template_id=…) |
POST /streams |
signal.streams.get(stream_id) |
GET /streams/:id |
signal.streams.cue(stream_id, response_action, …) |
POST /streams/:id/cue |
signal.streams.sandbox_topics() |
GET /sandbox-topics |
Responses are typed dataclasses with attribute access; each carries a .raw dict and a .meta legal/disclosure block you should not strip from buyer-facing surfaces.
Response actions
did_it · already_do · will_try · check_it · new_to_me · needed_this · know_it · acknowledge · no_response
Importable as RESPONSE_ACTIONS. The vocabulary grows over time; treat unknown values you receive as acknowledge-class.
Errors
from uphealth_signal import RateLimitError, ConflictError
try:
signal.streams.cue(stream_id, "did_it")
except RateLimitError as err:
show_upgrade(err.upgrade_url, err.current_count, err.cap)
except ConflictError as err:
if err.code == "feedback_required":
... # submit feedback on the prior cue first
| Class | Status | Notable attributes |
|---|---|---|
AuthenticationError |
401 | code |
PermissionDeniedError |
403 | required_scope |
NotFoundError |
404 | — |
ConflictError |
409 | code, last_cue_event_id, existing_event_id |
ValidationError |
422 | details, required, incompatible |
RateLimitError |
429 | retry_after, cap, current_count, window, upgrade_url |
ServiceUnavailableError |
503 | code |
APIConnectionError |
— | network/timeout |
All extend SignalError and carry status, code, request_id, and body.
Retries & idempotency
cue()is retry-safe: an idempotency key is generated if you don't pass one.5xxand network errors are retried with exponential backoff + jitter, up tomax_retries.create()is not auto-retried on ambiguous network errors (it isn't idempotent server-side yet).429is never auto-retried (the Discovery window resets monthly); handle it viaRateLimitError.
Links
- Docs: https://uphealth.us/docs
- OpenAPI spec: https://uphealth.us/openapi/signal-v1.yaml
- Get a sandbox key: https://uphealth.us/signup
License
MIT © Anschutz Media, Inc. (Uphealth)
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 uphealth_signal-0.1.0.tar.gz.
File metadata
- Download URL: uphealth_signal-0.1.0.tar.gz
- Upload date:
- Size: 13.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
43a51a503b0f1fe09d8c0b55afeef3ac2db5677e2d5b42861359dc34656d9485
|
|
| MD5 |
676dc84512a7c82f3b3e8ad52929e3f9
|
|
| BLAKE2b-256 |
39b3478a26f4ad536fe8fcb73a914f7953da00b1162ae966b7c393be91bb0d5c
|
Provenance
The following attestation bundles were made for uphealth_signal-0.1.0.tar.gz:
Publisher:
publish-python-sdk.yml on ericinsf/uphealth
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
uphealth_signal-0.1.0.tar.gz -
Subject digest:
43a51a503b0f1fe09d8c0b55afeef3ac2db5677e2d5b42861359dc34656d9485 - Sigstore transparency entry: 1819851964
- Sigstore integration time:
-
Permalink:
ericinsf/uphealth@ea62a1eea672848a200f2947f09f2382ceb2b6be -
Branch / Tag:
refs/heads/upgrade - Owner: https://github.com/ericinsf
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python-sdk.yml@ea62a1eea672848a200f2947f09f2382ceb2b6be -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file uphealth_signal-0.1.0-py3-none-any.whl.
File metadata
- Download URL: uphealth_signal-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
562dda8bef7c28d7fd084ed19a070e3c30aff94d201db645fd77a8d171417d15
|
|
| MD5 |
57f027f7197cde8b98f800bf451b67a2
|
|
| BLAKE2b-256 |
00559a869c0458ba8d93ddd1d07580dffddd097778acc7681036ec8642974520
|
Provenance
The following attestation bundles were made for uphealth_signal-0.1.0-py3-none-any.whl:
Publisher:
publish-python-sdk.yml on ericinsf/uphealth
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
uphealth_signal-0.1.0-py3-none-any.whl -
Subject digest:
562dda8bef7c28d7fd084ed19a070e3c30aff94d201db645fd77a8d171417d15 - Sigstore transparency entry: 1819852061
- Sigstore integration time:
-
Permalink:
ericinsf/uphealth@ea62a1eea672848a200f2947f09f2382ceb2b6be -
Branch / Tag:
refs/heads/upgrade - Owner: https://github.com/ericinsf
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python-sdk.yml@ea62a1eea672848a200f2947f09f2382ceb2b6be -
Trigger Event:
workflow_dispatch
-
Statement type: