Bulk Export

The Bulk Export system implements the FHIR Bulk Data Access specification, enabling you to export large datasets asynchronously in NDJSON format. It is ideal for data migrations, analytics pipelines, compliance reporting, and population health management.

How Bulk Export Works

Bulk exports are asynchronous. The flow is:

  1. Kick off an export — receive a 202 Accepted with a polling URL
  2. Poll the status URL until the export is complete (200 OK)
  3. Download the output files from the provided URLs
  4. Delete the export job when done

System-Level Export

Export all resources across your organization:

curl "https://api.esus.health/fhir/\$export" \
  -H "Authorization: Bearer TOKEN" \
  -H "Accept: application/fhir+json" \
  -H "Prefer: respond-async"

Response: 202 Accepted

Content-Location: https://api.esus.health/bulk-export/aa11bb22-cc33-dd44-ee55-ff6677889900

Filter by Resource Type

curl "https://api.esus.health/fhir/\$export?_type=Patient,Observation,Condition" \
  -H "Authorization: Bearer TOKEN" \
  -H "Prefer: respond-async"

Filter by Date

# Only resources modified since a specific date
curl "https://api.esus.health/fhir/\$export?_since=2024-01-01T00:00:00Z" \
  -H "Authorization: Bearer TOKEN" \
  -H "Prefer: respond-async"

Patient-Level Export

Export all resources for all patients in your organization:

curl "https://api.esus.health/fhir/Patient/\$export" \
  -H "Authorization: Bearer TOKEN" \
  -H "Prefer: respond-async"

Check Export Status

Poll the Content-Location URL to check progress:

curl https://api.esus.health/bulk-export/aa11bb22-cc33-dd44-ee55-ff6677889900 \
  -H "Authorization: Bearer TOKEN"

In Progress — 202 Accepted

{
  "status": "in-progress",
  "message": "Export in progress (2340 / 8500 resources processed)",
  "progress": 0.28
}

Complete — 200 OK

{
  "transactionTime": "2024-01-15T10:30:00Z",
  "request": "https://api.esus.health/fhir/$export",
  "requiresAccessToken": true,
  "output": [
    {
      "type": "Patient",
      "url": "https://api.esus.health/bulk-export/aa11bb22-cc33-dd44-ee55-ff6677889900/Patient.ndjson",
      "count": 1240
    },
    {
      "type": "Observation",
      "url": "https://api.esus.health/bulk-export/aa11bb22-cc33-dd44-ee55-ff6677889900/Observation.ndjson",
      "count": 5820
    },
    {
      "type": "Condition",
      "url": "https://api.esus.health/bulk-export/aa11bb22-cc33-dd44-ee55-ff6677889900/Condition.ndjson",
      "count": 980
    }
  ],
  "error": []
}

Download Export Files

Output files are in NDJSON (newline-delimited JSON) format — one FHIR resource per line:

curl "https://api.esus.health/bulk-export/aa11bb22-cc33-dd44-ee55-ff6677889900/Patient.ndjson" \
  -H "Authorization: Bearer TOKEN" \
  -o patients.ndjson

Sample patients.ndjson:

{"resourceType":"Patient","id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","meta":{"versionId":"3","lastUpdated":"2024-01-10T08:00:00Z"},"name":[{"family":"Smith","given":["John"]}],"birthDate":"1985-03-15"}
{"resourceType":"Patient","id":"bb22cc33-dd44-ee55-ff66-778899001122","meta":{"versionId":"1","lastUpdated":"2024-01-12T14:00:00Z"},"name":[{"family":"Doe","given":["Jane"]}],"birthDate":"1990-07-22"}

Cancel an Export

If you no longer need an export or want to free up resources:

curl -X DELETE https://api.esus.health/bulk-export/aa11bb22-cc33-dd44-ee55-ff6677889900 \
  -H "Authorization: Bearer TOKEN"

Returns 204 No Content on success.

Processing NDJSON in Common Languages

Node.js

import { createReadStream } from 'fs'
import { createInterface } from 'readline'

const rl = createInterface({ input: createReadStream('patients.ndjson') })

rl.on('line', (line) => {
  const patient = JSON.parse(line)
  console.log(patient.id, patient.name?.[0]?.family)
})

Python

import json

with open('patients.ndjson') as f:
    for line in f:
        patient = json.loads(line)
        print(patient['id'], patient.get('name', [{}])[0].get('family'))

Use Cases

Use CaseRecommended Export
Full data migrationSystem-level $export without filters
Incremental syncSystem-level $export?_since=<last-sync-date>
Analytics on clinical data$export?_type=Patient,Observation,Condition
Compliance audit export$export?_type=AuditEvent&_since=<period-start>
Population healthPatient-level Patient/$export