Some operations are computationally intensive and can take minutes or hours (bulk export, search-parameter reindexing, full resource revalidation). Running them asynchronously prevents blocking the client and lets the server manage the load. In an async flow the client kicks off the job, the server runs it in the background, and the client either polls for status or receives a callback when it completes.
Kick-off request -> 202 Accepted with Content-Location.
Status request (while running) -> 202 Accepted with Retry-After and optionally X-Progress.
Optional cancel -> DELETE to the status URL returns 202 Accepted.
Terminal status -> either 200 OK (payload inline) or 303 See Other (redirect to the payload).
Highlighted Text
Inline modes (Bundle, Bulk manifest) always return 200 OK on completion; success vs. failure is indicated by the payload (e.g., a result Bundle vs. an OperationOutcome, or error links inside a manifest). Redirect mode surfaces the original synchronous status codes on the redirected request (e.g., 200/201 on success, 4XX/5XX on failure).
The patterns mainly differ by the envelope for the final payload:
Bulk Data Access returns a custom JSON manifest.
Asynchronous Interaction Request returns a FHIR Bundle.
Redirect mode returns whatever the synchronous interaction would have returned (Parameters, Bundle, Binary, etc.).
This breaks down when the payload cannot be expressed as a Bundle (e.g., streaming outputs or binary content).
Highlighted Text
R6 work aims to standardize async across all interactions. Each interaction now allows 202 Accepted, and Josh's draft spec proposes an additional redirect pattern: the terminal status response is 303 See Other with a Location pointing to the result; that endpoint returns the actual payload and its status.
Highlighted Text
Ideally, we can unify these patterns into a single parameterized one. Use Prefer: respond-async plus a custom Prefer token to request the mode. For backward compatibility the default is bundle; if _outputFormat is present, treat the request as Bulk and return a manifest (servers MAY reject a conflicting async-mode with 400 Bad Request).
GET /fhir/[$operation] HTTP/1.1Prefer: respond-async, async-mode=[redirect|bundle] # async-mode is a proposed extension token
Highlighted Text
Servers SHOULD echo honored preferences via Preference-Applied..
Highlighted Text
Clients should assume unknown Prefer tokens are ignored and be prepared to fall back to the default bundle mode.
When the operation is completed:
Highlighted Text
async-mode=bundle: server SHOULD respond with 200 OK and a Bundle body; failures use an OperationOutcome payload.
_outputFormat parameter present: server SHOULD respond with 200 OK and a Bulk Manifest body; failures surface via manifest error links and/or an OperationOutcome entry.
async-mode=redirect: server SHOULD respond with 303 See Other and a Location URL pointing to the result of the operation; the redirected request returns the same status codes as the synchronous interaction.
Clients can infer completion and the mode from the status code (200 or 303); success vs. failure depends on the final payload or the redirected response status.
Extensions
Here is a list of extra extensions which can be added to improve support for async operations:
Long polling extension
Servers may use long polling for status requests to minimize latency. The server keeps the connection open until the operation is completed or a timeout occurs. On timeout the client retries, and the server controls the frequency of incoming status requests. Long polling reduces needless polling traffic while still delivering fast notification when the state changes (completion or cancellation).
Callback extension
Purpose: allow the server to notify the client when a job finishes so the client can pause or stop polling.
Motivation: callbacks keep response latency low without aggressive polling. Clients can back off to slow, cheap polls (or none) while still getting near-real-time notification when the job finishes.
Flow:
Highlighted Text
Client includes callback-url with Prefer: respond-async (and optional async-mode).
When the job completes or is cancelled, the server sends one POST to that URL.
If the callback fails or never arrives, the client relies on polling.
resultUrl (URL the client can fetch for the final payload)
Optional OperationOutcome parameter when the job failed
Delivery: best-effort, no retries; callbacks are a signal, not the primary delivery channel (polling is). Callbacks SHOULD be idempotent so duplicates are harmless.
Security: servers SHOULD authenticate callbacks (e.g., OAuth2 bearer token, mTLS, or HMAC).
Client handling: respond with 2XX on success; non-2XX just means the client will poll.
Read our Case Studies and see some of the work we’ve done for our clients.
Learn how Aidbox can help you handle all your healthcare data the right way.
Visit our Blog for the latest FHIR and digital health stories and resources.
Oops! Something went wrong while submitting the form.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
By clicking “Subscribe” you agree to Health Samurai Privacy Policy and consent to Health Samurai using your contact data for newsletter purposes
By using this website, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts. View our Cookie Policy for more information.
By using this website, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts. View our Cookie Policy for more information.