File Storage
The File Storage API lets you upload, retrieve, and delete files associated with your organization. Files are stored with organization-scoped isolation. The most common use case is attaching clinical documents, lab reports, imaging files, or signed consent forms to FHIR DocumentReference or Media resources.
Before storing, every upload passes through:
- Magic-byte + extension + MIME consistency check — mismatches are rejected with
415. - Antivirus scan — when ClamAV is configured, infected files are rejected with
422. - Tenant binding — files are stored under the caller’s organization; cross-tenant access is not possible.
Upload a File
Files are uploaded via multipart/form-data. Maximum file size is 50 MB.
curl -X POST https://api.esus.health/files/upload \
-H "Authorization: Bearer TOKEN" \
-F "file=@/path/to/lab-report.pdf"
Response:
{
"key": "3fa85f64-5717-4562-b3fc-2c963f66afa6/a1b2c3d4e5f6a7b8.pdf",
"contentType": "application/pdf",
"size": 245760,
"url": "/files/3fa85f64-5717-4562-b3fc-2c963f66afa6/a1b2c3d4e5f6a7b8.pdf"
}
The key is the storage path (<orgId>/<fileId>). The url is the relative path where the file can be downloaded; prefix it with the API host to build an absolute URL. The content-type in the response is the server-detected MIME (not the client-declared one) — it is what you should store in attachment.contentType.
Supported Content Types (examples)
| Type | Common use |
|---|---|
application/pdf | Clinical documents, consent forms, reports |
image/jpeg, image/png | Medical photography, wound documentation |
text/plain | Structured text reports |
application/json | Data exports, structured results |
video/mp4 | Procedural recordings |
The validator enforces a whitelist of clinical content types. Request additions through support when you have a legitimate use case.
Download a File
curl "https://api.esus.health/files/3fa85f64-5717-4562-b3fc-2c963f66afa6/a1b2c3d4e5f6a7b8.pdf" \
-H "Authorization: Bearer TOKEN" \
-o downloaded-report.pdf
By default the response uses Content-Disposition: attachment to prevent HTML/SVG/PDF from being rendered in-origin (XSS via uploaded content). Image-preview flows can opt in via ?disposition=inline. Cross-organization reads are refused with 403.
Delete a File
curl -X DELETE "https://api.esus.health/files/3fa85f64-5717-4562-b3fc-2c963f66afa6/a1b2c3d4e5f6a7b8.pdf" \
-H "Authorization: Bearer TOKEN"
Returns 204 No Content on success. Deletion is permanent — files are not recoverable afterwards.
Linking Files to FHIR Resources
After uploading, reference the file URL from a FHIR resource. Remember that the patient reference is sent as a flat id (subjectId), not as a nested FHIR reference object.
DocumentReference (lab report)
curl -X POST https://api.esus.health/fhir/DocumentReference \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/fhir+json" \
-d '{
"status": "current",
"type": {
"coding": [{
"system": "http://loinc.org",
"code": "11502-2",
"display": "Laboratory report"
}]
},
"subjectId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"date": "2026-04-21",
"content": [{
"attachment": {
"contentType": "application/pdf",
"url": "https://api.esus.health/files/3fa85f64-5717-4562-b3fc-2c963f66afa6/a1b2c3d4e5f6a7b8.pdf",
"title": "Lab report Apr 21",
"size": 245760
}
}]
}'
Media (clinical image)
curl -X POST https://api.esus.health/fhir/Media \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/fhir+json" \
-d '{
"status": "completed",
"type": {
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/media-type",
"code": "image"
}]
},
"subjectId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"createdDateTime": "2026-04-21",
"content": {
"contentType": "image/jpeg",
"url": "https://api.esus.health/files/3fa85f64-5717-4562-b3fc-2c963f66afa6/b2c3d4e5f6a7b8c9.jpg"
}
}'
Upload Limits and Best Practices
| Limit | Value |
|---|---|
| Maximum file size | 50 MB |
| Protocol | HTTPS only |
| Tenant isolation | Scoped to the caller’s organization |
Best practices:
- Link uploaded files to FHIR resources immediately — orphan files consume storage and lose clinical context.
- Use the server-detected
contentTypefrom the upload response when writing the attachment. - Delete files when the associated FHIR resource is deleted.
- For large imaging files (>50 MB), use a dedicated DICOM/PACS system and reference the external URL in
Media.content.url.