sha-claim
Python SDK for Social Health Authority (SHA, Kenya) claims through the Digital Health Agency's AfyaConnect HIE eClaims API. Async-first, typed, framework-free.
Status: pre-release (
0.1.0.dev0). All 49 published endpoints implemented. Eligibility, benefits and consent are verified live against DHA UAT; the claim lifecycle (ClaimSession) is contract-tested against the published spec and awaits a UAT beneficiary with a reachable phone for live verification. See PLAN.md.
Install
pip install sha-claim
Configure
Credentials come from DHA onboarding. The facility is implied by the credential (it is embedded in the token).
export SHA_ENVIRONMENT=uat # uat | production (production also needs SHA_BASE_URL)
export SHA_CLIENT_ID=...
export SHA_CLIENT_SECRET=...
Use
import asyncio
from datetime import date
from sha_claim import AsyncSHAClient, IdentificationType, BadRequestError
async def main() -> None:
async with AsyncSHAClient.from_env() as sha:
try:
e = await sha.eligibility.check("12345678", IdentificationType.NATIONAL_ID)
except BadRequestError as err: # server-side validation, carries trace_id
print(err.trace_id, err)
return
if e.is_covered_on(date.today()):
print(e.full_name, e.patient_id, [s.name for s in e.active_schemes_on(date.today())])
asyncio.run(main())
A claim, end to end
from sha_claim import (
AsyncSHAClient,
Money,
Otp,
ServiceType,
DocumentType,
Attachment,
SubmissionOutcomeUnknownError,
)
async with AsyncSHAClient.from_env() as sha:
patient = (await sha.eligibility.check("12345678", IdentificationType.NATIONAL_ID)).patient_id
coverage = await sha.eligibility.interventions(patient, "SHA-12-SC-01")
consultation = next(c for c in coverage if c.name == "Consultation")
# 1. consent: this sends the OTP to the beneficiary's registered phone
auth = await sha.consent.authorize(
patient, consultation.service_type_for_authorization, [consultation.code]
)
# 2. open the server-side virtual claim with the OTP the patient read out
session = await sha.claims.open_visit(
patient, consultation.service_type_for_authorization, [consultation.code], Otp("123456")
)
# 3. build it — every call is keyed by the session's consent_token
await session.add_diagnosis("1A00", consultation.code)
await session.add_line(consultation.code, Money.kes("1500"), quantity=1, diagnoses=["1A00"])
await session.attach(Attachment.from_path("invoice.pdf", DocumentType.INVOICE), consultation.code)
# 4. verify, then submit exactly once
preview = await session.preview()
try:
claim = await session.submit(invoice_number="INV-2026-000123")
except SubmissionOutcomeUnknownError:
claim = await session.preview() # the server knows whether it went through; ask it
# later, from any process that persisted the token:
status = await sha.claims.resume(claim.consent_token).payer_status("INV-2026-000123")
Every error is a subclass of sha_claim.SHAClaimError; see sha_claim.errors.
New to the SDK? Read the Consumer Guide — every method, its parameters, the HTTP call it makes, and the object it returns, plus end-to-end recipes.
Design in one paragraph
The server owns the claim: you open a virtual claim, receive a consent_token, mutate the claim
call by call, then submit. The SDK mirrors that faithfully — it holds snapshots, not a local
state machine — and only rejects locally what the server will certainly reject. Reads are retried
with backoff; submit is attempted exactly once. Layers follow Clean Architecture and are enforced
by import-linter. Details: docs/ARCHITECTURE.md; API reference generated
from the official portal: docs/api/.
Develop
make install # venv + editable install with dev extras
make check # ruff, mypy --strict, import-linter, pytest (≥ 90 % coverage)
make live # RUN_LIVE=1: smoke tests against DHA UAT (needs .env)
License
Apache-2.0
Release files for sha-claim 0.1.8
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sha_claim-0.1.8.tar.gz | 147.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sha_claim-0.1.8-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 225.3 kB
Release files / sha_claim-0.1.8.tar.gz
| Download URL | sha_claim-0.1.8.tar.gz |
|---|---|
| Size | 147.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5a1f09e4711cc51ee3d9d9cf557f5f92c189a32b844fd2fa706d4ec53c8d391d
|
|
BLAKE2b-256 checksum How to use checksums |
f11c6492ce0caa14acd64afd3a2571df7b8912a0e5aa86c03c39cdccd238a24c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency logRelease files / sha_claim-0.1.8-py3-none-any.whl
| Download URL | sha_claim-0.1.8-py3-none-any.whl |
|---|---|
| Size | 78.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4daf09c53e97d44cc40877cfac0f62db598bb9a1431f51342f5fa850673bfc70
|
|
BLAKE2b-256 checksum How to use checksums |
8cd91598882614e0bab3fa88c70f482c9e7e9c91ebb87e58029d785dfa2a612d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.
Transparency log