Personal Health Records, published by HL7 International / Patient Empowerment. This guide is not an authorized publication; it is the continuous build for version 1.0.0-ballot2 built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/HL7/personal-health-record-format-ig/ and changes regularly. See the Directory of published versions
| Page standards status: Informative |
Systems MAY implement standard APIs for generating and importing .phr or .sphr files. These operations enable patients to export their complete health records from one system and import them into another, supporting the core PHR use case of patient-controlled data portability.
The $phr-export operation generates a complete patient health record in various formats. This operation is typically invoked by the patient or their authorized application.
# Export as FHIR Bundle (default)
GET /Bundle/$phr-export
# Export as NDJSON Bulk Data file
GET /Bundle/$phr-export?outputFormat=ndjson
# Export as PHR file (NDJSON with .phr extension)
GET /Bundle/$phr-export?outputFormat=phr
# Export as secure SPHR file (encrypted zip container)
GET /Bundle/$phr-export?outputFormat=sphr
Date Range Filtering:
Exporters can request specific time periods to reduce payload size or focus on recent data:
# Export everything from 2010 to current
GET /Bundle/$phr-export?start=2010
# Export specific date range
GET /Bundle/$phr-export?start=2010&end=2020-06
# Export last year only
GET /Bundle/$phr-export?start=2024-01-01&end=2024-12-31
Multi-Patient Systems:
For systems managing multiple patients (e.g., EHR systems), specify the patient identifier:
# Export for specific patient
GET /Bundle/$phr-export?patient=Patient/12345
# Export with date range and format
GET /Bundle/$phr-export?patient=Patient/12345&outputFormat=sphr&start=2020
The $import operation accepts PHR data in NDJSON format and imports it into the receiving system. This operation should handle deduplication, provenance tracking, and conflict resolution.
# Import PHR data (NDJSON format)
POST /Bundle/$import
Content-Type: application/x-ndjson
# Import with merge strategy
POST /Bundle/$import?strategy=merge
# Import with validation only (no commit)
POST /Bundle/$import?mode=validate
Import Considerations:
Export operations support multiple response formats:
| Format | MIME Type | Description |
|---|---|---|
| Bundle | application/fhir+json |
Standard FHIR Bundle resource |
| NDJSON | application/x-ndjson |
Newline-delimited JSON, one resource per line |
| PHR | application/x-ndjson |
Same as NDJSON with .phr extension |
| SPHR | application/zip |
Encrypted zip containing .phr file(s) plus supporting documents |
PHR systems following the PHR FHIR Implementation Guide MUST include the API endpoints they are exposing in the PHR's FHIR server's CapabilityStatement:
{
"resourceType": "CapabilityStatement",
"rest": [{
"mode": "server",
"operation": [
{
"name": "phr-export",
"definition": "http://hl7.org/fhir/uv/phr/OperationDefinition/phr-export"
},
{
"name": "import",
"definition": "http://hl7.org/fhir/uv/phr/OperationDefinition/phr-import"
}
]
}]
}
SMART Health Links (SHLinks) provide a mechanism for patients to share their health records via QR codes or short URLs. A SMART Health Link encodes an API endpoint URL along with a decryption key, enabling secure, convenient data sharing without requiring pre-established technical connectivity.
A SMART Health Link QR code encodes a URL in the format:
shlink:/eyJ1cmwiOiJodHRwczovL...
When scanned, the QR code provides access to an API endpoint that returns encrypted health data. The decryption key is embedded in the link itself.
A SMART Health Link URL payload contains:
{
"url": "https://example.org/api/shl/abc123",
"key": "rxTgYlOaKJPFtcEd0qcceN8wEU4p94SqAwIWQe6uX7Q",
"exp": 1735689600,
"flag": "LP",
"label": "Patient Health Summary"
}
| Field | Description |
|---|---|
url |
API endpoint where encrypted payload can be retrieved |
key |
Base64url-encoded decryption key (256-bit AES-GCM) |
exp |
Optional expiration time (Unix timestamp) |
flag |
L = long-term, P = passcode required, U = single use |
label |
Human-readable description |
SMART Health Links use A256GCM (AES-256 in Galois/Counter Mode). The payload retrieved from the URL is a JWE (JSON Web Encryption) that can be decrypted using the embedded key.
When sharing via SMART Health Link:
While the .phr format is primarily designed for file-based storage and exchange, systems may also transmit PHR data directly over HTTP connections using streaming techniques.
When transmitting .phr content over HTTP, use the following headers:
Content-Type: application/x-ndjson
Content-Disposition: attachment; filename="patient-record.phr"
X-PHR-Version: 1.0
For FHIR-aware systems:
Content-Type: application/fhir+ndjson
NDJSON format is well-suited for streaming because each line is a complete, parseable JSON object. Receivers can process records as they arrive without waiting for the complete transmission, enabling:
Server (streaming response):
// Node.js example
response.setHeader('Content-Type', 'application/x-ndjson');
response.setHeader('Transfer-Encoding', 'chunked');
for await (const resource of patientResources) {
response.write(JSON.stringify(resource) + '\n');
}
response.end();
Client (streaming consumption):
// Process each line as it arrives
const readline = require('readline');
const rl = readline.createInterface({ input: response });
rl.on('line', (line) => {
const resource = JSON.parse(line);
processResource(resource);
});
| Aspect | PHR Format | Bulk Data IG |
|---|---|---|
| File structure | Single heterogeneous .ndjson | Separate file per resource type |
| Typical use | Single patient export | Multi-patient population export |
| Resource ordering | Patient-centric, mixed types | Grouped by resourceType |
| Streaming | Well-suited | Designed for batch |
The PHR format uses a single file with mixed resource types for patient-centric simplicity, while Bulk Data separates by type (Observation.ndjson, Condition.ndjson, etc.) for scalability with large populations.
For streaming transfers, errors may occur mid-stream. Recommended approach:
{"resourceType":"OperationOutcome","issue":[{"severity":"error","code":"processing","diagnostics":"Error at line 847: invalid reference"}]}
Include OperationOutcome resources inline to indicate processing errors while allowing the stream to continue for partial data recovery.