Submit Shield de-identifying client SDK — strips PHI locally, validates remotely.
Project description
Submit Shield SDK
De-identify claims locally. Validate remotely. PHI never leaves your network.
The Submit Shield SDK is the client-side half of Submit Shield. It runs inside your clinic's network, strips every HIPAA identifier out of each claim before the claim leaves your machine, and posts only the de-identified payload to the Submit Shield validation API. Verdicts come back and the SDK re-hydrates them locally with your real patient context so your billers see real names in their UI while Submit Shield servers only ever see pseudonyms.
This is not a promise — it's an architectural property. The SDK writes an append-only SHA-256 attestation log on every call proving which bytes went out, and those bytes contain no PHI by construction. Your HIPAA officer can audit the log without ever sharing a single patient record.
Why this exists
Traditional claim scrubbers (Waystar, Optum, FinThrive, Availity) all operate under a Business Associate Agreement because they handle raw PHI. That means every customer signs a BAA, every vendor passes PHI to every downstream system, and every breach notification covers everyone.
Submit Shield instead chose to never receive PHI in the first place. Under 45 CFR §164.514(b) (HIPAA Safe Harbor), health information with the 18 enumerated identifiers removed is not PHI and can be disclosed without authorization. The Submit Shield SDK performs that removal on the customer's side of the wire, so Submit Shield's servers are not a Business Associate for any customer using it.
Install
Pick whichever delivery mode fits your environment:
# Python (Linux, macOS, any Python 3.10+ environment)
pip install submitshield
# Docker (any OS with Docker)
docker pull submitshield/sdk:latest
# Windows (standalone .exe, no Python required)
# Download from https://submitshield.health/downloads/submitshield-setup.exe
Configure
The SDK needs two things:
- The Submit Shield API URL —
https://api.submitshield.health - A customer secret — a stable random string (≥32 chars) that you generate once and keep in your infrastructure. This is the HMAC key used to pseudonymize member IDs. It never leaves your network.
# Linux / macOS
export SUBMITSHIELD_API_URL=https://api.submitshield.health
export SUBMITSHIELD_CUSTOMER_SECRET="$(openssl rand -hex 32)"
echo "$SUBMITSHIELD_CUSTOMER_SECRET" > /secure/submitshield.secret
# Windows (PowerShell, as administrator)
[System.Environment]::SetEnvironmentVariable('SUBMITSHIELD_API_URL', 'https://api.submitshield.health', 'Machine')
# For the secret, generate with:
[System.Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))
Validate a claim
# CSV
submitshield validate patient_claims.csv
# FHIR R4 Bundle
submitshield validate patient_claims.fhir.json
# Canonical Claim JSON
submitshield validate claim.json
# Multiple files at once
submitshield validate *.csv --output verdicts.json
Watch a folder
Drop claim files into a folder and let the SDK process them automatically:
submitshield watch /var/spool/submitshield/inbox
# Or with the Docker image
docker run -d --name submitshield \
-e SUBMITSHIELD_API_URL=https://api.submitshield.health \
-e SUBMITSHIELD_CUSTOMER_SECRET="$(cat /secure/submitshield.secret)" \
-v /var/spool/submitshield/inbox:/inbox \
-v /var/spool/submitshield/verdicts:/outbox \
-v /var/submitshield:/var/submitshield \
submitshield/sdk:latest
Inspect the attestation log
Every de-identification call is logged with two SHA-256 hashes — one over the input, one over the de-identified payload. The log is append-only JSONL so it's compatible with every log-rotation tool.
# Last 20 entries
submitshield attest --last 20
# Raw log (feed it to your SIEM)
cat $SUBMITSHIELD_ATTESTATION_LOG
A typical record:
{
"timestamp": "2026-04-11T19:04:32.118203+00:00",
"sdk_version": "0.1.0",
"hostname": "clinic-workstation-3",
"pid": 4812,
"format": "csv_row",
"original_sha256": "a1b2c3d4e5f60708...",
"deidentified_sha256": "9f8e7d6c5b4a3928...",
"pseudonym_count": 1,
"stripped_fields": [
"patient_first_name",
"patient_last_name",
"patient_zip",
"patient_dob"
],
"server_url": "https://api.submitshield.health",
"server_request_id": "req_abc123"
}
What the SDK strips
Safe Harbor requires removing 18 identifiers. The SDK handles each one:
| # | Identifier | How we handle it |
|---|---|---|
| 1 | Names | Replaced with REDACTED |
| 2 | Geographic subdivisions smaller than state | Street/city/zip dropped; state retained for MAC routing |
| 3 | Dates (except year) related to the individual | DOB reduced to {year}-01-01; DoS optionally shifted |
| 4 | Phone numbers | Stripped |
| 5 | Fax numbers | Stripped |
| 6 | Email addresses | Stripped |
| 7 | SSN | Stripped |
| 8 | Medical record numbers | HMAC pseudonym |
| 9 | Health plan beneficiary / member numbers | HMAC pseudonym |
| 10 | Account numbers | HMAC pseudonym |
| 11 | Certificate / license numbers | Stripped |
| 12 | Vehicle identifiers | Stripped |
| 13 | Device identifiers / serial numbers | Stripped |
| 14 | URLs | Stripped |
| 15 | IP addresses | Stripped |
| 16 | Biometric identifiers | Not present in claim data |
| 17 | Full-face photographs | Not present in claim data |
| 18 | Any other unique identifying number | HMAC if it looks like an identifier column |
Provider NPIs are not stripped. NPIs are public data (NPPES is the CMS public registry) and are not HIPAA identifiers for the patient.
Remote updates
The SDK checks GET {api_url}/sdk/version on startup (cached 1 hour) and:
- Same version: silent.
- Newer available: prints an upgrade notice; the call proceeds.
- Current version below minimum supported: refuses to run. This is the kill-switch for critical privacy fixes.
To force an upgrade from the server side:
# Publish a new SDK release
hatch build && hatch publish
docker buildx build -t submitshield/sdk:0.1.1 -t submitshield/sdk:latest --push .
# Then update the API's environment
SUBMITSHIELD_SDK_LATEST_VERSION=0.1.1
SUBMITSHIELD_SDK_MIN_SUPPORTED_VERSION=0.1.1 # forces every client to upgrade
Any customer whose SDK hits /sdk/version after this will get the
kill-switch response on their next call.
Questions
- "What if my internet is down?" The update check is best-effort; a network failure during the check does not block validation. Your SDK will keep running with the last successfully-fetched version metadata until connectivity returns.
- "Can I use this under a BAA if I want to?" Yes. Set
SUBMITSHIELD_DEIDENTIFY=falseand the SDK passes PHI through unmodified. Your Submit Shield account must be on the BAA-tier plan for this to be accepted on the server side. - "Can I self-host the API?" Yes, at the Enterprise tier. See https://submitshield.health/enterprise.
- "What happens if the Submit Shield API is down?" The SDK fails fast with a clear error message. The raw claim file is untouched — you can re-run when the API is back.
- "How do you prove my PHI never left my network?" The attestation
log carries the hash of the original input and the hash of the
outgoing payload. An auditor can hash any PHI field that was present
in the original and confirm that hash appears only in the
original_sha256column and never in thedeidentified_sha256column or the API request logs.
License
Proprietary — Submit Shield customer license. See docs/sdk_license.txt.
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 submitshield-0.1.0.tar.gz.
File metadata
- Download URL: submitshield-0.1.0.tar.gz
- Upload date:
- Size: 33.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c99af0968d41356f6cfd09a28b49b14f0b716669ab2d8e7b52e70e809a9bc806
|
|
| MD5 |
517da25e091c51f98a90bd27b50cd927
|
|
| BLAKE2b-256 |
149dc42db11afeef7c2db6e8d73d1ed3417a33b8e8787cf2c805a35bd9468bd4
|
File details
Details for the file submitshield-0.1.0-py3-none-any.whl.
File metadata
- Download URL: submitshield-0.1.0-py3-none-any.whl
- Upload date:
- Size: 25.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a8ac910fb78705ad7a8b01f7dbfaa6642caeced8359e58063a063e53d0a3d865
|
|
| MD5 |
473f3ad29f34e2ee2bdd592913af9a76
|
|
| BLAKE2b-256 |
7e61291671d6d22bb24be691518277a758b544bae3ca495711ffcda0d0c74806
|