The short answer
FHIR Bulk Data $export is an asynchronous operation that exports large sets of FHIR resources as files: for all patients, for a group, or for the whole server.1 The implementation guide requires TLS 1.2 or later for all exchanges, recommends OAuth 2.0 access management under the SMART Backend Services profile, and, when that’s used, says status requests and output-file requests marked requiresAccessToken must be protected like the kick-off, with a token whose scopes cover all resources being exported.1
For AI agents, the policy is simple: an agent shouldn’t be able to start an export. If a workflow needs population data, a person or a scheduled job starts it with its own credentials, and the agent works on a narrow, approved extract.
This is about data access and records security, not clinical use of the data.
Deedglass
The server said “saved”. Deedglass looked.
Deedglass reads it back
The three export endpoints
| Endpoint | Exports1 | Blast radius |
|---|---|---|
[fhir base]/Patient/$export |
Resources of many types for all patients | Every patient on the server |
[fhir base]/Group/[id]/$export |
Resources for all members of a Group | Every member of that group |
[fhir base]/$export |
Data from the server whether or not tied to a patient, e.g. for backups or terminology exports via _type |
The whole server |
Parameters narrow it: _type limits resource types, _since returns only resources changed after a time, and _typeFilter applies FHIR search criteria per type.1 Narrowing helps, but the default for a system-level export is everything.
How the flow works
From the implementation guide:1
- Kick-off. The client calls an
$exportendpoint withPrefer: respond-async. - Accepted. The server answers
202 Acceptedwith aContent-Locationheader: the polling URL. - Poll. The client polls that URL until the export completes. The server may return a partial manifest with files that are ready, then update it.
- Download. The completion manifest lists output file URLs, in NDJSON; the client downloads them.
- Delete. The client may send
DELETEto the polling URL to cancel, or, after completion, to signal it’s done so the server can remove the files; later polls then return404.1
Two details matter for security. The output files are separate URLs, which may or may not require an access token. And the guide doesn’t set one approach for how long files stay available: it supports an Expires header and leaves removal to the server implementer, while saying servers shouldn’t delete files a client is actively downloading.1
What the spec requires for security
From the guide’s privacy and security considerations:1
| Requirement | Strength |
|---|---|
| TLS 1.2 or later on all exchanges | SHALL |
| Mutual TLS | OPTIONAL |
| OAuth 2.0 access management per SMART Backend Services | SHOULD |
With Backend Services: status and output-file requests with requiresAccessToken=true protected like the kick-off, with scopes covering all exported resources |
SHALL |
| Restricting status and file requests to the client that started the export | MAY |
| Access control through in-band (OAuth scopes) and out-of-band restrictions | Described as the way to meet obligations |
Read the “MAY” row twice. Unless your server restricts status and file requests to the originating client, another client with a sufficiently scoped token may be able to reach them. Check how your server behaves.
Why agents and bulk export don’t mix
An agent with a Backend Services token that can call $export holds, in one tool call, the ability to copy every patient’s records to files. Three things make that worse than an ordinary read:
- The scale is the operation’s purpose. A read tool returns one resource; an export returns the population.
- The data leaves in files. Once downloaded, the files are outside the FHIR server’s access controls and audit trail.
- It’s asynchronous. A kick-off, a poll and a download can be spread across steps, each looking harmless on its own.
That’s the lethal trifecta with the private-data leg turned up to its maximum. The blast radius of a confused or steered agent is everyone.
Questions to ask your FHIR vendor
Bulk Data behaviour varies by server. Before any agent goes near a server that supports $export, get answers to:
- Which clients can call
$export, and with which scopes? You want a short, named list. - Do output files require an access token? And is that token checked against the client that started the export?1
- How long do files live? Whether the server sets an
Expiresheader, and when it removes files.1 - Is every kick-off, poll and file download logged with the client identity?
- Can a gateway rule block
$exportfor some clients regardless of their scopes?
Write the answers down next to your agent’s access policy. They decide how bad the worst day could be.
An agent policy for bulk data
- No export scopes in agent tokens. Agents get SMART scopes for the resources and patients their task needs; our post on SMART on FHIR v2 scopes covers granular scopes. Export rights live with a separate backend client.
- Block the operation at the gateway. A rule that refuses any agent request whose path ends in
$export, regardless of scopes, is cheap insurance. - Exports started by people or schedules, with
_typeand_sinceset to the minimum, and files deleted after use with theDELETErequest.1 - Agents work on extracts. If an analysis needs population data, give the agent a de-identified, approved extract, not the export pipeline.
- Restrict file access to the originating client, where your server supports it.1
- Log every kick-off with the client, parameters and file count.
A checklist
- TLS 1.2 or later on every Bulk Data exchange.
- SMART Backend Services for export clients, with scopes limited to what each export needs.
- Output files require access tokens and expire.
- File and status requests restricted to the originating client where possible.
- No agent token can start an export; a gateway rule blocks
$exportfrom agents. - Exports deleted after download.
- Every export logged and reviewed.
For agent writes on FHIR servers, see AI agents writing to patient records; for the basics, the FHIR glossary entry. To see what the agents configured on your machine could reach, paste the config into the check page or run npx deedglass scan (how the grade works); to try tool-call rules in your browser, open the playground.
Written with AI assistance and checked against our claims register.