> The FHIR Asynchronous Interaction Request Pattern API is under active development. Participate in design discussions at [chat.fhir.org](https://chat.fhir.org/).
## Asynchronous Interaction Request Pattern
### Use Case
All interactions defined in the [RESTful API](http.html) are synchronous by default. For interactions that may require significant processing time, servers can offer an asynchronous mode so the client does not need to wait for a response.
This pattern, based on [RFC 7240](https://tools.ietf.org/html/rfc7240#section-4.1), applies to [Operations](operations.html) and [Defined Interactions](http.html) that a server elects to process asynchronously.
For example, an operation like `$reindex`, which might be used to process millions of `Observation` resources against a new `SearchParameter`, is an ideal candidate for this pattern. A synchronous request would likely time out, but an asynchronous request allows the client to submit the job and check on its status later. The final result of a successful `$reindex` operation is typically a `Parameters` resource summarizing the outcome.
#### Related Pattern: Asynchronous Bulk Data Request
For exporting bulk/large result sets (e.g., all `Patient` resources), see the [Asynchronous Bulk Data Request](async-bulk.html) pattern. When the `_outputFormat` parameter is present in a request, the Bulk Data pattern SHALL be used.
### Visual Overview: Sequence Diagram
This diagram shows the complete lifecycle of an asynchronous request, including the paths for a job that is cancelled versus one that runs to completion, and the outcomes for a completed job that either succeeds or fails.
```mermaid
sequenceDiagram
participant Client
participant Server
Note over Client,Server: Step 1: Kick-off
Client->>Server: POST /.../$reindex (Prefer: respond-async)
Server->>Client: 202 Accepted (Content-Location: /whatever/path/1ab7162f-status)
alt Job is Cancelled by Client
Note over Client,Server: Step 3: Delete (Cancel)
Client->>Server: DELETE /whatever/path/1ab7162f-status
Server->>Client: 202 Accepted (Cancellation acknowledged)
Note right of Client: Subsequent polls would result in 404 Not Found.
else Job Runs to Completion
loop Polling Loop (Step 2)
Client->>Server: GET /whatever/path/1ab7162f-status
Server->>Client: 202 Accepted (Retry-After: 60)
end
Client->>Server: GET /whatever/path/1ab7162f-status (Final poll)
Server->>Client: 303 See Other (Location: /whatever/path/1ab7162f-result)
Note over Client,Server: Job execution is complete. Now fetch the final result.
alt Job Succeeded (Step 4)
Client->>Server: GET /whatever/path/1ab7162f-result
Server->>Client: 200 OK (Body: Parameters)
else Job Failed (Step 4)
Client->>Server: GET /whatever/path/1ab7162f-result
Server->>Client: 500 Internal Server Error (Body: OperationOutcome)
end
end
```
---
### 1. Kick-off Request
The kick-off request uses the same HTTP method, URL, and body as the corresponding synchronous interaction, but adds a `Prefer` header to signal the asynchronous request.
> **Note on URLs in Examples:** Throughout this specification, example URLs use paths like `/whatever/path/1ab7162f-status` and `/whatever/path/1ab7162f-result` for clarity. Servers may choose any URL structure for status and result endpoints. Clients must treat all URLs returned by the server (in `Content-Location` and `Location` headers) as opaque values and should not parse or construct them.
#### Headers
* **`Accept`** (string)
* Specifies the format for any `OperationOutcome` returned immediately at kick-off or for transient polling errors. A client SHOULD provide this header. If omitted, the server MAY choose a format or return an error.
* **`Prefer`** (string, **required**)
* Must be set to `respond-async` to request asynchronous processing.
#### Example: Kicking off a `$reindex` Operation
Here, the client asks the server to re-index all `Observation` resources for a new search parameter.
```http
POST /fhir/Observation/$reindex HTTP/1.1
Host: fhir.example.com
Accept: application/fhir+json
Prefer: respond-async
Content-Type: application/fhir+json
{
"resourceType": "Parameters",
"parameter": [
{
"name": "url",
"valueUrl": "http://example.org/fhir/SearchParameter/observation-special-code"
}
]
}
```
#### Response - Success
If the server accepts the job, it returns `202 Accepted` with a `Content-Location` header pointing to a status polling URL.
* **HTTP Status Code:** `202 Accepted`
* **`Content-Location`:** An absolute URL for polling the job's status.
* **Body (Optional):** An `OperationOutcome` or other resource with informational details.
#### Example: Server Response for `$reindex` Kick-off
```http
HTTP/1.1 202 Accepted
Content-Location: https://fhir.example.com/whatever/path/1ab7162f-status
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"issue": [{
"severity": "information",
"code": "informational",
"details": { "text": "Re-indexing job accepted and is now in progress." }
}]
}
```
#### Response - Error
If the server rejects the request (e.g., due to invalid parameters or lack of permissions), it returns a standard `4XX` or `5XX` error.
* **HTTP Status Code:** `4XX` or `5XX`
* **Body:** An `OperationOutcome` explaining the error.
---
### 2. Status Request (Polling)
Clients poll the URL from the `Content-Location` header using an HTTP `GET` to check the job's status. Clients SHOULD implement an [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) strategy.
Servers SHOULD include a [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) header (in seconds or as an HTTP-date) to guide the client's polling frequency. If a client polls too frequently, the server SHOULD return `429 Too Many Requests`.
#### Response - In Progress
While the job is still running, the server responds with `202 Accepted`.
* **HTTP Status Code:** `202 Accepted`
* **Headers:**
* `Retry-After`: (Optional) Suggests when to make the next request.
* `X-Progress`: (Optional) A short string describing the current progress (e.g., "55% complete").
* **Body (optional):** A `Parameters` or other resource with informational details.
#### Example: In-Progress Poll for `$reindex`
```http
GET /whatever/path/1ab7162f-status HTTP/1.1
Host: fhir.example.com
Accept: application/fhir+json
```
```http
HTTP/1.1 202 Accepted
Retry-After: 60
X-Progress: Indexed 550,000 of 1,200,000 resources.
```
#### Response - Complete
When the job is finished (whether it succeeded or failed), the server responds with `303 See Other`. The `Location` header points to the final result.
* **HTTP Status Code:** `303 See Other`
* **Headers:**
* `Location`: The absolute URL of the final result resource or endpoint.
* **Body:** Body is empty. The final result must be fetched from the `Location` URL.
#### Example: Completed Poll for `$reindex`
```http
GET /whatever/path/1ab7162f-status HTTP/1.1
Host: fhir.example.com
Accept: application/fhir+json
```
```http
HTTP/1.1 303 See Other
Location: https://fhir.example.com/whatever/path/1ab7162f-result
```
---
### 3. Delete Request (Cancel)
The client MAY send an HTTP `DELETE` to the polling URL to request cancellation of the job. On success, the server SHOULD clean up any associated data. Subsequent polls to this URL MUST return `404 Not Found`.
#### Response - Success
* **HTTP Status Code:** `202 Accepted`
* **Body (Optional):** An `OperationOutcome`.
#### Example: Cancelling the `$reindex` Job
```http
DELETE /whatever/path/1ab7162f-status HTTP/1.1
Host: fhir.example.com
```
```http
HTTP/1.1 202 Accepted
Content-Type: application/fhir+json
{
"resourceType": "OperationOutcome",
"issue": [{
"severity": "information",
"code": "informational",
"details": { "text": "Job cancellation requested." }
}]
}
```
---
### 4. Fetch the Result
After receiving a `200 OK` from the polling URL with a `Location` header, the client performs a final `GET` against that `Location` URL to retrieve the outcome of the operation.
The response from this final `GET` is **exactly what the synchronous interaction would have returned**. This includes the status code (e.g., `200 OK` for success, `422 Unprocessable Entity` for a business rule error), standard headers (`ETag`, `Last-Modified`), and the body (e.g., a `Parameters` resource for an operation, a resource for a create, a `Bundle` for a search).
#### Example: Fetching the Successful `$reindex` Result
The client fetches the result and receives the final `Parameters` resource indicating success.
```http
GET /whatever/path/1ab7162f-result HTTP/1.1
Host: fhir.example.com
Accept: application/fhir+json
```
```http
HTTP/1.1 200 OK
Content-Type: application/fhir+json; charset=utf-8
ETag: W/"1ab7162f-final"
Last-Modified: Fri, 01 Mar 2024 14:05:10 GMT
{
"resourceType": "Parameters",
"parameter": [
{
"name": "status",
"valueCode": "completed"
},
{
"name": "durationInSeconds",
"valueDecimal": 742.5
},
{
"name": "resourcesScanned",
"valueUnsignedInt": 1200000
},
{
"name": "indexEntriesCreated",
"valueUnsignedInt": 1457890
},
{
"name": "processingSummary",
"part": [
{
"name": "resourcesIndexedSuccessfully",
"valueUnsignedInt": 1198540
},
{
"name": "resourcesSkippedNoMatchingPath",
"valueUnsignedInt": 1458
},
{
"name": "resourcesSkippedWithError",
"valueUnsignedInt": 2
}
]
},
{
"name": "message",
"valueString": "Re-indexing complete. 2 resources failed validation and were skipped."
}
]
}
```
#### Example: Fetching a Failed `$reindex` Result
If the re-indexing job failed internally, the final result is an error. The polling status would still return `200 OK` (because the job has *completed*), but fetching the result reveals the failure.
```http
GET /whatever/path/1ab7162f-result HTTP/1.1
Host: fhir.example.com
Accept: application/fhir+json
```
```http
HTTP/1.1 500 Internal Server Error
Content-Type: application/fhir+json; charset=utf-8
{
"resourceType": "OperationOutcome",
"issue": [{
"severity": "error",
"code": "exception",
"details": { "text": "Job failed due to an unexpected database connection error during indexing." }
}]
}
```
1) What errors are synchronous vs. asynchronous?
- Minimal answer: Invalid input/auth -> 4XX/5XX immediately. Otherwise -> 202 async; runtime failures surface at result time.
2) How do clients know an operation supports async?
- Minimal answer: Clients send `Prefer: respond-async`. If unsupported, server returns 400. Operation Definitions can publish human-readable description stating that async executation is allowed or reqiured.
- Richer answer: define extensions on `OperationDefinition` to indicate async-behavior (allowed | required | ...)