There are three distinct ways to POST bundles:
POST /Bundle — store a Bundle resource (e.g., document, collection); no operational processing.
POST / with Bundle.type=”transaction” — execute an atomic, all-or-nothing set of operations.
POST / with Bundle.type=”batch” — execute best-effort independent operations (not atomic).
Use this when you want to store a Bundle itself (e.g., document, collection) – not execute operations.
Endpoint:
POST https://{baseurl}/Bundle
Behavior:
{
"resourceType": "Bundle",
"type": "document",
"entry": [
{
"resource": {
"resourceType": "Composition",
"status": "final",
"type": { "coding": [ { "system": "http://loinc.org", "code": "34133-9" } ] }
}
}
]
}
POST https://{baseurl}
Bundle requirement: Bundle.type = “transaction”{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"fullUrl": "urn:uuid:patient-123",
"resource": {
"resourceType": "Patient",
"identifier": [
{ "system": "https://acme.org/mrns", "value": "12345" }
],
"name": [
{ "family": "Jameson", "given": [ "J", "Jonah" ] }
],
"gender": "male"
},
"request": {
"method": "POST",
"url": "Patient",
"ifNoneExist": "identifier=https://acme.org/mrns|12345"
}
},
{
"resource": {
"resourceType": "Observation",
"status": "final",
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "789-8",
"display": "Erythrocytes [#/volume] in Blood by Automated count"
}
]
},
"subject": { "reference": "urn:uuid:patient-123" },
"valueQuantity": {
"value": 4.12,
"unit": "10 trillion/L",
"system": "http://unitsofmeasure.org",
"code": "10*12/L"
}
},
"request": { "method": "POST", "url": "Observation" }
}
]
}
Notes:
POST https://{baseurl}
Bundle requirement: Bundle.type = “batch”{
"resourceType": "Bundle",
"type": "batch",
"entry": [
{ "request": { "method": "DELETE", "url": "Organization/1" } },
{ "request": { "method": "DELETE", "url": "Organization/2" } }
]
} When loading data from multiple sources, references may point to resources that haven’t been created yet (e.g., an Observation referencing a Patient). You have three patterns to handle this. Pattern A is pure FHIR and recommended; Patterns B–C are server-specific and are included as reference-only for environments that enable them.
A) Transaction with Conditional Create (recommended, standard FHIR)
Use a single transaction bundle and “upsert” the target using request.ifNoneExist. Link intra-bundle resources with entry.fullUrl URNs.
Behavior:
All entries are processed as one atomic unit; any failure rolls back the whole bundle.
ifNoneExist performs a conditional create using a standard search expression (e.g., identifier=system|value).
entry.fullUrl URNs let other entries reference the newly created resource.
Example (atomic Patient + Observation via URN link):
{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"fullUrl": "urn:uuid:patient-123",
"resource": {
"resourceType": "Patient",
"identifier": [
{ "system": "https://acme.org/mrns", "value": "12345" }
],
"name": [
{ "family": "Jameson", "given": [ "J", "Jonah" ] }
],
"gender": "male"
},
"request": {
"method": "POST",
"url": "Patient",
"ifNoneExist": "identifier=https://acme.org/mrns|12345"
}
},
{
"resource": {
"resourceType": "Observation",
"status": "final",
"code": {
"coding": [
{
"system": "http://loinc.org",
"code": "789-8",
"display": "Erythrocytes [#/volume] in Blood by Automated count"
}
]
},
"subject": { "reference": "urn:uuid:patient-123" },
"valueQuantity": {
"value": 4.12,
"unit": "10 trillion/L",
"system": "http://unitsofmeasure.org",
"code": "10*12/L"
}
},
"request": { "method": "POST", "url": "Observation" }
}
]
}
B) Inline Match-URL References (reference-only; server-specific)
Some servers allow a Reference.reference to contain a match URL (e.g., Patient?identifier=system|value). The server treats it as a local search and either links to the match or creates a new target.
Status on Opala public APIs: not exposed. If enabled in a managed environment, the typical behavior is:
0 results: create the target and replace the match URL with a concrete reference.
1 result: replace with the found target.
>1 results: operation fails (ambiguous).
Example (reference-only):
{
"resourceType": "Observation",
"status": "final",
"code": { "coding": [ { "system": "http://loinc.org", "code": "789-8" } ] },
"subject": {
"reference": "Patient?identifier=https://foo|1234",
"identifier": { "system": "https://foo", "value": "1234" }
},
"valueQuantity": {
"value": 4.12,
"system": "http://unitsofmeasure.org",
"code": "10*12/L"
}
}Note on Reference.identifier: If both the match URL and Reference.identifier are present, servers may add one or both identifiers to the created target; rules vary by implementation. This pattern is not standard FHIR behavior and should be used only where explicitly supported.
C) Auto-Creating Placeholder Targets (reference-only; vendor-specific)
Some stacks support auto-creating an empty resource when you reference a non-existent ID (e.g., Patient/ABC). This is not part of core FHIR and isn’t exposed on Opala’s public APIs.
Typical behaviors (if enabled)
A minimal resource is created with the referenced ID.
Some servers tag these placeholders with a custom extension (e.g., http://hapifhir.io/fhir/StructureDefinition/resource-placeholder) and/or provide a custom SearchParameter (e.g., resource-placeholder=true) to find them.
Example (reference-only):
{
"resourceType": "Observation",
"status": "final",
"code": { "coding": [ { "system": "http://loinc.org", "code": "789-8" } ] },
"subject": { "reference": "Patient/ABC" },
"valueQuantity": {
"value": 4.12,
"system": "http://unitsofmeasure.org",
"code": "10*12/L"
}
} Cautions
Placeholders can leak partial/assumed state and complicate reconciliation.
If placeholders are created without an identifier, conditional updates later may be impossible; always prefer pattern A when you can.
The following are general best practices for large loads (reference-only; specifics vary by environment):
Prefer transactions for graph integrity, but keep bundles to a reasonable size to avoid timeouts and memory pressure.
Use conditional create/update to deduplicate by business identifiers.
Pre-validate resources and value sets where possible (e.g., $validate), and normalize codes/URIs ahead of time.
Avoid server-specific features (inline match URLs, placeholder auto-create) unless your environment explicitly supports them.
Coordinate with Opala for managed environments; performance tuning (threading, DB, indexing) is handled at the platform level.