Dashboard

SMART Health Links

SMART Health Links (SHL) enable secure, privacy-preserving sharing of health data via QR codes and short links. The @fhirfly-io/shl SDK provides everything you need to build IPS (International Patient Summary) bundles, encrypt them, and share them as scannable links.

CMS's "Kill the Clipboard" initiative mandates that patients should be able to carry their health records digitally. SHL is the emerging standard for this, backed by the HL7 FHIR community.

Feature Description
End-to-end encryption AES-256-GCM encryption. The decryption key lives only in the URL — never on the server.
QR code sharing Generate scannable QR codes that encode the entire SHL payload.
Passcode protection Optional passcode requirement for additional security.
Expiration & access limits Set time-based or count-based limits on link access.
IPS compliance Build International Patient Summary bundles with medications, conditions, allergies, immunizations, lab results, and documents.
PSHD compliance CMS-aligned Patient-Shared Health Document profile for point-of-care QR sharing with direct retrieval.
Expiration presets Named presets ("point-of-care", "appointment", "travel", "permanent") instead of manual Date math.
Audit logging AuditableStorage interface for storage-level access auditing with recipient tracking.

Architecture

The SHL SDK provides two complementary paths:

Zero-Infrastructure (FhirflyStorage)

Use FhirflyStorage to store encrypted content on FHIRfly's hosted service. No S3 buckets, no servers — just install the SDK and go. FhirflyStorage is included free in all plans with per-plan limits on active SHLs — see Pricing for details.

import { IPS, SHL } from "@fhirfly-io/shl";

const storage = new SHL.FhirflyStorage({
  apiKey: process.env.FHIRFLY_API_KEY,
});

const bundle = new IPS.Bundle({ name: "Jane Doe", birthDate: "1990-01-15" });
bundle.addMedication({ byNDC: "00071015523", fhirfly: client.ndc });
const fhirBundle = await bundle.build();

const result = await SHL.create({ bundle: fhirBundle, storage });
// result.url  → shlink:/eyJ...
// result.qrCode → data:image/png;base64,...

Bring Your Own Storage (BYOS)

Use S3, Azure Blob Storage, Google Cloud Storage, or local filesystem storage. Run your own SHL server with Express, Fastify, or AWS Lambda middleware.

const storage = new SHL.S3Storage({
  bucket: "my-shl-bucket",
  region: "us-east-1",
  baseUrl: "https://shl.myapp.com",
});

SDK Packages

Package Description
@fhirfly-io/shl Core SDK — IPS bundle building + SHL encryption
@fhirfly-io/shl/server Server middleware for hosting SHL endpoints
@fhirfly-io/shl/express Express adapter
@fhirfly-io/shl/fastify Fastify adapter
@fhirfly-io/shl/lambda AWS Lambda adapter

CLI

The SDK includes a CLI for common workflows:

npx @fhirfly-io/shl validate bundle.json   # Validate a FHIR Bundle
npx @fhirfly-io/shl create bundle.json     # Create an SHL from a bundle
npx @fhirfly-io/shl decode shlink:/eyJ...  # Decode an SHL URL
npx @fhirfly-io/shl serve                  # Start a local SHL server
npx @fhirfly-io/shl demo                   # Full round-trip demo

Live Exercise

The SDK includes a comprehensive integration test that exercises every path against the live API — bundle building, FhirflyStorage, LocalStorage + Express, consumption, access control, and edge cases. Run it to smoke-test your deployment or as a reference for SDK usage:

npx tsx examples/live-exercise/index.ts --api-key <key> --verbose

See the live exercise README for details.

Security

The SDK uses a zero-knowledge encryption architecture — the server never sees the decryption key. Read the Security & Compliance page for details on encryption, HIPAA considerations, rate limiting, and an implementer compliance checklist.

EHR Integration

Going from EHR data to a shareable QR code? The EHR Integration Guide covers mapping HL7v2, CCDA, FHIR R4, and flat database records to IPS bundles with complete code examples.

Viewer

FHIRfly provides a general-purpose SHL viewer that works with any shlink:/ URL. All decryption happens client-side in the browser — the encryption key never leaves the page.