Send Independent Requests in a Batch

Submit up to 25 independent FHIR requests in one R4 or R6 Ballot 4 batch Bundle.

Use a batch to send several independent requests together, such as a Patient search and an Observation search. Instead of making a separate HTTP call for each request, your application makes one call and receives the results together.

Each request has its own result, making it easier to see which requests succeeded and which need attention. Use a batch only when no request needs the result of another request in the same batch.

For the standard definitions of batch processing, see the HL7 FHIR R4 batch and transaction rules and the Batch entry in the HL7 FHIR R6 Ballot 4 glossary. DDFS supports batch requests; transaction bundles remain unsupported.

Choose the versioned endpoint

Check that the deployed server's CapabilityStatement advertises the system-level batch interaction. Send a POST to the FHIR base URL for the selected version, without a resource type or /Bundle suffix:

POST /api/fhir/r4
POST /api/fhir/r6-ballot4
Content-Type: application/fhir+json
Accept: application/fhir+json
Authorization: Bearer <access-token>

Use resources supported by that FHIR version. The token must authorize each requested resource interaction, just as for a separate request. See Authentication and Scopes.

Build the request

Set resourceType to Bundle and type to batch. Each entry needs an uppercase request.method and a request.url relative to the selected FHIR base URL. Supported methods are GET, POST, PUT, and DELETE for supported interactions. Include entry.resource when the interaction needs a resource body.

This read-only example works with either versioned endpoint. It performs two independent searches:

{
  "resourceType": "Bundle",
  "type": "batch",
  "entry": [
    {"request": {"method": "GET", "url": "Patient?_count=1"}},
    {"request": {"method": "GET", "url": "Observation?_count=1"}}
  ]
}

For PUT creation, replacement, and restoration, use the resource type and logical ID in the entry URL and include the same ID and resource type in its body. The same permissions and response rules apply as for a direct PUT.

Inspect every entry result

A successfully processed batch returns HTTP 200 with a Bundle whose type is batch-response. Entries are processed in request order and response entries correspond to request entries in that order. The outer HTTP status does not mean that every entry succeeded.

Inspect each entry.response.status. An entry can also include response.location, response.etag, response.lastModified, and a returned resource or error outcome, as applicable to its interaction. For example, two searches with no matches can return:

{
  "resourceType": "Bundle",
  "type": "batch-response",
  "entry": [
    {
      "resource": {"resourceType": "Bundle", "type": "searchset"},
      "response": {"status": "200 OK"}
    },
    {
      "resource": {"resourceType": "Bundle", "type": "searchset"},
      "response": {"status": "200 OK"}
    }
  ]
}

One entry can fail while unrelated entries succeed. Review the failed entry's OperationOutcome and HTTP status. A failed entry does not roll back successful writes from other entries. See OperationOutcome Errors.

Limits and unsupported behavior

  • A batch contains at most 25 entries. A larger batch is rejected with HTTP 400; divide the work into smaller batches.
  • Entries must be independent. Do not depend on another entry's response or reference a resource created by another entry in the same batch.
  • Transaction bundles and transaction rollback are unsupported.
  • Conditional entry request fields, including ifMatch, ifNoneMatch, ifModifiedSince, and ifNoneExist, are unsupported. Use a direct PUT when you need If-Match version protection.
  • Use relative entry URLs for the same FHIR version. Do not submit absolute service URLs or nested batch requests.