transaction-bundles
Makes a Bundle of type transaction atomic: every entry is applied, or none is. Without the feature, the same request is accepted but runs as a batch.
| Type | Project feature |
Value in features | transaction-bundles |
| Change with | PATCH /v1/projects/me/features (replaces the whole list) |
| Who can change it | Project admin. Any practitioner can read the list. |
| On for new projects | Yes |
| When off | A transaction Bundle runs as a batch: entries succeed or fail independently |
What it does
Send a Bundle whose type is transaction to the FHIR base:
curl --request POST \
--url 'https://api.sandbox.ovok.com/fhir/R4' \
--header "Authorization: Bearer ${OVOK_TOKEN}" \
--header 'Content-Type: application/fhir+json' \
--data @transaction-bundle.json
Example transaction-bundle.json. The Observation refers to the new Patient through a temporary urn:uuid id:
{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"fullUrl": "urn:uuid:5b1f0c0e-6f43-4c55-9d1a-0a6c2f6d1a11",
"resource": { "resourceType": "Patient", "name": [{ "family": "Example" }] },
"request": { "method": "POST", "url": "Patient" }
},
{
"resource": {
"resourceType": "Observation",
"status": "final",
"code": { "coding": [{ "system": "http://loinc.org", "code": "8867-4" }] },
"subject": { "reference": "urn:uuid:5b1f0c0e-6f43-4c55-9d1a-0a6c2f6d1a11" },
"valueQuantity": { "value": 72, "unit": "beats/minute" }
},
"request": { "method": "POST", "url": "Observation" }
}
]
}
What you get back
| Feature | Outcome |
|---|---|
| On, all entries succeed | 200 with a transaction-response Bundle. |
| On, one entry fails | The whole request is rejected with an OperationOutcome and nothing is written. The HTTP status is the failing entry's own (for example 404 when an entry reads a resource that does not exist). |
| Off, all entries succeed | 200 with a transaction-response Bundle. |
| Off, one entry fails | 200 with a transaction-response Bundle. The other entries are still written; read each entry's response.status. |
When the feature is on, expect these statuses for a rolled-back transaction: 412 when an entry's If-Match is stale, 409 when the database could not serialise concurrent writes, and 400 with a deadlock message when it detected a deadlock. Retry 409 and a deadlock 400; re-read before retrying 412.
Limits when it is on
| Limit | Result |
|---|---|
More than 50 update (PUT) entries | 400 Transaction contains more update operations than allowed |
A conditional create (ifNoneExist), conditional update or conditional delete with more than 8 entries in the Bundle | 400 Transaction requires strict isolation but has too many entries |
Prefer: respond-async on a transaction | 400 Transaction batches cannot be executed asynchronously |
Split work that exceeds the limits into several transactions, and keep each one a single logical change.
Turn it on
curl --request PATCH \
--url 'https://api.sandbox.ovok.com/v1/projects/me/features' \
--header "Authorization: Bearer ${OVOK_TOKEN}" \
--header 'Content-Type: application/json' \
--data '{"features":["bots","cron","email","transaction-bundles","websocket-subscriptions"]}'
Gotchas
- Off is silent. With the feature off, a transaction Bundle still returns
200, and the responsetypeis stilltransaction-response, so nothing in the response tells you it ran as a batch. A client that treats200as "everything was saved" can lose writes. Checktransaction-bundlesin the features list, and check each entry'sresponse.statuswhen you are not sure. - The flag is read from the project of the token that sends the Bundle, not from the project that owns the data.
- Projects created before this was a default can lack it. Call
GET /v1/projects/me/featuresand check.
Related
- Bundle
- Extract Observations from a QuestionnaireResponse, which returns a transaction Bundle you can post
- Check an async job's status