
SMART Health Links SDK
Build an International Patient Summary, encrypt it as a SMART Health Link, and generate a QR code — in under 20 lines of code.
Installation
npm install @fhirfly-io/shlIf using FHIRfly API enrichment (recommended — adds display names and SNOMED cross-mappings automatically):
npm install @fhirfly-io/shl @fhirfly-io/terminology1. Build an IPS Bundle
import { IPS, SHL } from "@fhirfly-io/shl";
import Fhirfly from "@fhirfly-io/terminology";
const client = new Fhirfly({ apiKey: process.env.FHIRFLY_API_KEY });
const bundle = new IPS.Bundle({
given: "Maria",
family: "Garcia",
birthDate: "1985-03-15",
gender: "female",
});
// Add clinical data (FHIRfly enriches with SNOMED, display names, etc.)
bundle.addMedication({ byNDC: "00071015523", fhirfly: client.ndc });
bundle.addCondition({ byICD10: "E11.9", fhirfly: client.icd10 });
bundle.addAllergy({ bySNOMED: "387207008" });
bundle.addImmunization({ byCVX: "208", fhirfly: client.cvx });
bundle.addResult({
byLOINC: "2339-0",
fhirfly: client.loinc,
value: 95,
unit: "mg/dL",
});
const fhirBundle = await bundle.build();Each add* method accepts multiple input formats: code-based with enrichment (byNDC, byICD10, byCVX, byLOINC), SNOMED direct (bySNOMED), existing FHIR resources (fromResource), or manual code/system/display.
No API key? Use bySNOMED (no API call needed) or manual code/system/display input. The FHIRfly API adds display names and SNOMED cross-mappings but isn't required.
2. Create an SHL
// Option A: FHIRfly hosted (zero infrastructure)
const storage = new SHL.FhirflyStorage({
apiKey: process.env.FHIRFLY_API_KEY,
});
// Option B: Local storage (for development)
// const storage = new SHL.LocalStorage({
// directory: "./shl-data",
// baseUrl: "http://localhost:3456/shl",
// });
const result = await SHL.create({
bundle: fhirBundle,
storage,
passcode: "1234",
label: "Maria's Health Summary",
});
console.log(result.url); // shlink:/eyJ...
console.log(result.qrCode); // data:image/png;base64,...This does four things:
- Generates a random 256-bit encryption key and SHL ID
- Encrypts the FHIR bundle as a JWE (AES-256-GCM, DEFLATE compression)
- Stores three files:
content.jwe,manifest.json,metadata.json - Builds the
shlink:/URL (with the key embedded) and a QR code PNG
FhirflyStorage is included free in all plans with per-plan limits on active SHLs and attachments. The decryption key is never sent to FHIRfly — only opaque encrypted blobs are stored. See Pricing and Storage Adapters for details.
3. Share
The result.url is a complete SMART Health Link. Share it by:
- QR Code — Save
result.qrCodeas a PNG image for scanning - Deep Link —
https://fhirfly.io/shl/viewer#shlink:/eyJ... - Text — Send the
shlink:/URL directly
4. View
Open the SHL Viewer and paste the link, or use the deep link format above. All decryption happens in the browser — the encryption key never leaves the page.
CLI alternative
For quick testing without writing code:
# Full demo with sample patient data
npx @fhirfly-io/shl demo
# Create from an existing FHIR Bundle file
npx @fhirfly-io/shl create my-bundle.json --passcode 1234
# Start a local server
npx @fhirfly-io/shl serve --dir ./shl-data --port 3456
# Validate a FHIR Bundle against IPS
npx @fhirfly-io/shl validate bundle.json
# Decode an SHL URL
npx @fhirfly-io/shl decode shlink:/eyJ...How encryption works
The SDK uses a zero-knowledge architecture. The encryption key lives only in the shlink:/ URL — it is never sent to the server. The server stores and serves opaque encrypted blobs. Only someone with the URL (or QR code) can decrypt the data.
| Data | Where it lives |
|---|---|
| Patient health data | Encrypted (AES-256-GCM) on your storage backend |
| Decryption key | Embedded in the shlink:/ URL only |
| Passcode | SHA-256 hashed in server metadata |
| Access controls | Server-side metadata (expiration, max accesses) |