Asynchronous processing is required for Patient360 network queries and several other operations. Health Gorilla recommends it for any long-running requests, such as $everything.
When you use the FHIR R4 API to query networks such as Carequality, CommonWell, eHealth Exchange, and TEFCA QHINs, the networks respond at different speeds and often return large results. Synchronous requests keep their HTTP connections open until the results return, and if that takes too long, the connections time out before you get the results. With asynchronous processing, Health Gorilla accepts your requests right away and completes them in the background.
Lifecycle
Each asynchronous request follows the same lifecycle:
- Accepted: You send the request with
Prefer: respond-async. A202 Acceptedresponse is returned, with aLocationheader that points to a/RequestResult/{id}URL. - Processing: The request runs in the background. If you send a
GETrequest to the/RequestResult/{id}URL before it finishes, you get a second202 Accepted, which means the result isn't ready yet. - Complete: The result is stored with the original request's status code and body.
- Notified: If you have a subscription with the criteria
OperationOutcome?async=true, Health Gorilla posts anOperationOutcometo your endpoint. Without a subscription, you poll theLocationURL. - Retrieved: You get the result from
/RequestResult/{id}. If a retrieval fails, you can retrieve the result again until it expires. - Expired: About one hour after processing completes, the result expires, and
/RequestResult/{id}returns454 Expired or Not Found.
How It Works
To use asynchronous processing, include the Prefer: respond-async header in your requests. The header is the only change. Otherwise, your authentication and request payloads stay the same.
Note: Leave the header off
PATCHrequests, since they can't be processed asynchronously.
There's no account-level setting, so you add the header in one of two ways:
- On every request: Set it as a default header in your HTTP client. Every call then gets a
202 Accepted, and your integration retrieves each result from/RequestResult/{id}, including quick reads. - Per request: Send the header on the operations that require it, listed under Requirements, and on other requests you expect to run long, such as
$everything. Other requests stay synchronous and return their results directly.
Example: Asynchronous Request
GET /fhir/R4/Patient/65e4a45c3c266fc4e5d45c72/$cq-search HTTP/1.1
Host: api.healthgorilla.com
Authorization: Bearer {access_token}
Prefer: respond-asyncExample: 202 Accepted Response
Instead of the result, you receive a 202 Accepted response, which means the request was accepted, not that it succeeded. For POST, PUT, and DELETE requests, check the status of the stored result to learn the outcome. The Location header carries the path of the pending result, on the same host as your original request. The X-Hg-Request-Id value identifies the request for troubleshooting, and it's the same ID that ends the Location URL.
HTTP/1.1 202 Accepted
Location: /fhir/R4/RequestResult/3ce13b5ecb4d6633826caca0
Preference-Applied: respond-async
X-Hg-Request-Id: 3ce13b5ecb4d6633826caca0Requirements
Asynchronous processing is available for GET, POST, PUT, and DELETE requests that carry an Authorization header.
Some operations require the Prefer: respond-async header and, without it, return 400 Bad Request with the code async-required. These include:
- Network searches for patient documents, such as
$cq-search,$cw-search,$ehex-search,$qhin-search,$hghin-search, and$p360-search - Record retrieval across networks, with
$p360-retrieve - Bulk data export, with
$export - C-CDA export of a patient's record, with
Patient$export-ccda - Draft order submission, with
RequestGroup$submit - Several requests in one call, with
Bundlebatch and transaction requests
Getting the Result
There are two ways to learn that an asynchronous result is ready. If your system can accept inbound HTTP requests, use webhooks to be notified when the result is ready. If it can't accept inbound HTTP requests, use polling even if it requires repeated calls and may delay retrieval. Either way, you retrieve the result from its /RequestResult/{id} URL.
Webhooks
To receive webhook notifications, create a Subscription resource with the criteria OperationOutcome?async=true and the payload application/fhir+json. For setup and security details, go to Subscribing to Events and Webhook Delivery & Security.
Notifications arrive at your registered endpoint with /OperationOutcome added to the end. For example, if you register https://yourapp.com/webhooks, notifications arrive at https://yourapp.com/webhooks/OperationOutcome.
A completion notification carries only the RequestResult URL, not the result. Because notifications are sent whether or not the request succeeded, check the status of the result when you retrieve it from that URL.
Example: Completion Notification
A completion notification is an OperationOutcome with the request ID in issue.id and the result URL in issue.expression.
{
"resourceType": "OperationOutcome",
"issue": [
{
"id": "3ce13b5ecb4d6633826caca0",
"severity": "information",
"details": {
"coding": [
{
"system": "http://hl7.org/fhir/operation-outcome",
"code": "MSG_CREATED",
"display": "New resource created"
}
],
"text": "New resource created"
},
"expression": ["/fhir/R4/RequestResult/3ce13b5ecb4d6633826caca0"]
}
]
}Failed deliveries are retried every 15 minutes, but the result still expires about one hour after processing completes. If a notification doesn't arrive, poll the Location URL.
Polling
To poll, send GET requests to the Location URL from the 202 Accepted response until the result is ready. Polling for an asynchronous result is different from polling for new or updated resources with _lastUpdated, covered on Polling.
Example: Polling Request
GET /fhir/R4/RequestResult/3ce13b5ecb4d6633826caca0 HTTP/1.1
Host: api.healthgorilla.com
Authorization: Bearer {access_token}While the request is processing, you receive 202 Accepted. Its Retry-After header gives the minimum number of seconds to wait before polling again. Start with that wait, and lengthen it after each 202 Accepted. When processing is complete, you receive the original request's response, and after the result expires, 454 Expired or Not Found.
Status Codes
Responses from /RequestResult/{id} use these HTTP statuses.
| HTTP Status | Meaning |
|---|---|
| 202 Accepted | The request is still processing. The response carries X-Progress: in progress and a Retry-After header. |
| 200 OK, or the original request's status | The result is complete. A failed request returns its own error status, such as 404 Not Found or 429 Too Many Requests. |
| 403 Forbidden | The access token is missing, invalid, or expired. |
| 454 Expired or Not Found | The result expired, typically one hour after processing completes, or the ID isn't recognized. |
| 500 Internal Server Error | Processing failed, or the result couldn't be retrieved. |
Best Practices
- Log the
X-Hg-Request-Idvalue and theRequestResultURL for each request, so you can correlate jobs and troubleshoot. - Secure your webhook endpoint with HTTPS, authentication, and sender validation.

